chore(release): v0.5.0 #80

Merged
alex merged 1 commit from release-prep/rolling into main 2026-06-26 00:40:30 +02:00

Added

v0.5.0 docs lock-in — the final slice of the v0.4.0 architectural arc (#52).

  • docs/integration.md rewritten for the v0.4.0+ shape — push: branches: [main] trigger, rolling-PR mechanic, single _release.yml reusable (no more separate release-draft.yml). Added two new sections: (a) Fragment summary: frontmatter explaining the (B1) release-notes/CHANGELOG bifurcation + the quote-your-#-references convention with the empirical YAML-comment-truncation regression guard; (b) Branch protection compatibility explaining the (B) manifest-via-PR cut-path mechanic + the auto-merge fallback behavior.

  • AGENTS.md (new) — the implementer pre-flight checklist for contributors touching _release.yml / release-prep.sh / draft-release.sh / lib/fragments.sh. Codifies the carry-forward enumeration discipline (predecessor-step audit; Surveyor ec4c framing), the self-bootstrap re-pin pattern (Surveyor b7e7 axis-sharpening — mechanism-of-touch, not version-magnitude), the YAML / awk / bash gotchas surfaced during the v0.4.0–v0.5.0 arc, cut-verification-as-load-bearing (Surveyor d64a), decision-tree-not-conclusion in PR bodies, source-grounded vs invented claims (Surveyor 5bbe placebo-test catch + 6a82 stale-clone-origin-main self-correction), and the filed-root-cause-is-hypothesis discipline. Each item is anchored to the specific empirical catch that surfaced it.

  • docs/migration/v0.3-to-v0.5.md (new) — step-by-step migration guide for v0.3.x consumers moving to v0.5.0. Covers the release.yml rewrite, release-draft.yml deletion, manifest bootstrap, branch-protection check, and optional summary: frontmatter retrofit. Includes a rollback section — @v0.3.x workflows remain published, no forced cutover.

  • changelog.d/78-cut-path-manifest-via-pr.fixed.md updated with a summary: frontmatter so the v0.5.0 release-notes body is concise (operator-flagged on the v0.4.0 cut; per Surveyor 015d's sequencing flag this had to land in slice 5 before the v0.5.0 cut to avoid shipping the long fallback in production release notes).

Closes #52 slice 5.

Fragment frontmatter (B1) — release-notes vs CHANGELOG.md bifurcation. Fragments now accept an optional YAML frontmatter with a summary: field that feeds into the Forgejo release-notes body without affecting CHANGELOG.md composition (the full body still lands there, verbatim, for repo history / developer audience). The release-notes pipeline reads .release-toolkit-release-notes.md (a sidecar written by release-prep.sh from fragment summaries grouped by kind); draft-release.sh consumes the sidecar as the release body, falling back to the CHANGELOG section when the sidecar is absent (v0.3.x behavior preserved).

Authors can opt in by adding frontmatter to any fragment:

---
summary: 'Short consumer-facing summary, quoted because of #N references.'
---

Long-form prose for the CHANGELOG.md section — substrate-honest context,
root-cause analysis, design tradeoffs, all the developer-audience detail
that would clutter the release page but belongs in repo history.

Quoting is required when the summary contains # (YAML treats unquoted # as start-of-comment; the bats suite includes a regression guard demonstrating the truncation behavior so the convention is enforced empirically, not just documented). Block-scalar form (summary: |) is also supported for multi-line summaries.

Fragments without frontmatter continue to work unchanged — the fallback path uses the first non-empty paragraph of the body as the summary. Backward-compatible; opt-in per fragment.

Lighter sibling of ADR-0006 path (a3) — bifurcates the prose without bifurcating the lifecycle (sidecar overwrites each cut; CHANGELOG.md accumulates). Closes #77.

  • fragments: release-notes/CHANGELOG bifurcation via summary frontmatter (closes #77)

Fixed

_release.yml cut path + lib/forgejo-api.sh: the cut path now opens a PR for the manifest update instead of direct-pushing to main, then attempts to auto-merge via the Forgejo API. Previously the workflow's GITHUB_TOKEN got rejected by the pre-receive hook on any branch-protected main (where apply_to_admins: false); the cut completed the draft release but left the manifest update stranded. The new path is self-contained — no admin-scope tokens required from consumers (path (B) in #78, operator-selected over (A) admin-PAT for the security-surface asymmetry). New helpers forgejo_merge_pr + forgejo_create_issue_comment added to lib/forgejo-api.sh. If auto-merge fails (e.g., branch protection still forbids the workflow token from merging), the PR sits open with an explanatory comment and manual-merge instructions in the body. Closes #78.

  • _release: manifest update via PR instead of direct-push to main (closes #78)
### Added **v0.5.0 docs lock-in** — the final slice of the v0.4.0 architectural arc ([#52](https://git.frankenbit.de/frankenbit/release-toolkit/issues/52)). - **`docs/integration.md`** rewritten for the v0.4.0+ shape — `push: branches: [main]` trigger, rolling-PR mechanic, single `_release.yml` reusable (no more separate `release-draft.yml`). Added two new sections: (a) **Fragment `summary:` frontmatter** explaining the (B1) release-notes/CHANGELOG bifurcation + the quote-your-`#`-references convention with the empirical YAML-comment-truncation regression guard; (b) **Branch protection compatibility** explaining the (B) manifest-via-PR cut-path mechanic + the auto-merge fallback behavior. - **`AGENTS.md`** (new) — the implementer pre-flight checklist for contributors touching `_release.yml` / `release-prep.sh` / `draft-release.sh` / `lib/fragments.sh`. Codifies the carry-forward enumeration discipline (predecessor-step audit; Surveyor ec4c framing), the self-bootstrap re-pin pattern (Surveyor b7e7 axis-sharpening — mechanism-of-touch, not version-magnitude), the YAML / awk / bash gotchas surfaced during the v0.4.0–v0.5.0 arc, cut-verification-as-load-bearing (Surveyor d64a), decision-tree-not-conclusion in PR bodies, source-grounded vs invented claims (Surveyor 5bbe placebo-test catch + 6a82 stale-clone-origin-main self-correction), and the filed-root-cause-is-hypothesis discipline. Each item is anchored to the specific empirical catch that surfaced it. - **`docs/migration/v0.3-to-v0.5.md`** (new) — step-by-step migration guide for v0.3.x consumers moving to v0.5.0. Covers the `release.yml` rewrite, `release-draft.yml` deletion, manifest bootstrap, branch-protection check, and optional `summary:` frontmatter retrofit. Includes a rollback section — `@v0.3.x` workflows remain published, no forced cutover. - **`changelog.d/78-cut-path-manifest-via-pr.fixed.md`** updated with a `summary:` frontmatter so the v0.5.0 release-notes body is concise (operator-flagged on the v0.4.0 cut; per Surveyor 015d's sequencing flag this had to land in slice 5 before the v0.5.0 cut to avoid shipping the long fallback in production release notes). Closes [#52](https://git.frankenbit.de/frankenbit/release-toolkit/issues/52) slice 5. **Fragment frontmatter (B1) — release-notes vs CHANGELOG.md bifurcation.** Fragments now accept an optional YAML frontmatter with a `summary:` field that feeds into the Forgejo release-notes body without affecting CHANGELOG.md composition (the full body still lands there, verbatim, for repo history / developer audience). The release-notes pipeline reads `.release-toolkit-release-notes.md` (a sidecar written by `release-prep.sh` from fragment summaries grouped by kind); `draft-release.sh` consumes the sidecar as the release body, falling back to the CHANGELOG section when the sidecar is absent (v0.3.x behavior preserved). Authors can opt in by adding frontmatter to any fragment: ```markdown --- summary: 'Short consumer-facing summary, quoted because of #N references.' --- Long-form prose for the CHANGELOG.md section — substrate-honest context, root-cause analysis, design tradeoffs, all the developer-audience detail that would clutter the release page but belongs in repo history. ``` Quoting is required when the summary contains `#` (YAML treats unquoted `#` as start-of-comment; the bats suite includes a regression guard demonstrating the truncation behavior so the convention is enforced empirically, not just documented). Block-scalar form (`summary: |`) is also supported for multi-line summaries. Fragments without frontmatter continue to work unchanged — the fallback path uses the first non-empty paragraph of the body as the summary. Backward-compatible; opt-in per fragment. Lighter sibling of ADR-0006 path (a3) — bifurcates the prose without bifurcating the lifecycle (sidecar overwrites each cut; CHANGELOG.md accumulates). Closes [#77](https://git.frankenbit.de/frankenbit/release-toolkit/issues/77). - **fragments**: release-notes/CHANGELOG bifurcation via summary frontmatter (closes #77) ### Fixed **`_release.yml` cut path + `lib/forgejo-api.sh`**: the cut path now opens a PR for the manifest update instead of direct-pushing to `main`, then attempts to auto-merge via the Forgejo API. Previously the workflow's `GITHUB_TOKEN` got rejected by the pre-receive hook on any branch-protected `main` (where `apply_to_admins: false`); the cut completed the draft release but left the manifest update stranded. The new path is self-contained — no admin-scope tokens required from consumers (path **(B)** in [#78](https://git.frankenbit.de/frankenbit/release-toolkit/issues/78), operator-selected over **(A)** admin-PAT for the security-surface asymmetry). New helpers `forgejo_merge_pr` + `forgejo_create_issue_comment` added to `lib/forgejo-api.sh`. If auto-merge fails (e.g., branch protection still forbids the workflow token from merging), the PR sits open with an explanatory comment and manual-merge instructions in the body. Closes [#78](https://git.frankenbit.de/frankenbit/release-toolkit/issues/78). - **_release**: manifest update via PR instead of direct-push to main (closes #78)
Owner

RETRACTED — #80 is the legitimate v0.4.1 rolling PR. Handle normally. (My original comment below said "spurious — do not merge"; that was a timing misread, corrected here.)

Verified at source: #79 merged at 23:28:55 (fast-forward → main = 297477e); #80 was created at 23:29:02, 7s later, with base == merge_base == 297477e == main's actual tip. It was opened correctly by the push:main event from #79's merge — not from feature content. No spurious PR, no Forgejo trigger bug.

My "ahead of main" conclusion compared #80's base against my scratch clone's origin/main, which was a stale pre-merge snapshot (cloned in the ~30s window before the merge, never re-fetched). Apologies for the noise. #80 will auto-retarget (e.g. to v0.5.0 once #77's feat content lands) per the update-path force-reset.


⚠️ Spurious rolling PR — do not merge. This branch is built on the unmerged #79 feature commits; base.ref reads main but merge_base is 297477e, mergeable. Merging would prematurely cut v0.4.1… (struck — incorrect, see above)

✅ **RETRACTED — #80 is the legitimate v0.4.1 rolling PR. Handle normally.** (My original comment below said "spurious — do not merge"; that was a timing misread, corrected here.) Verified at source: #79 merged at **23:28:55** (fast-forward → main = `297477e`); #80 was created at 23:29:02, **7s later**, with `base == merge_base == 297477e ==` main's actual tip. It was opened correctly by the `push:main` event from #79's merge — not from feature content. No spurious PR, no Forgejo trigger bug. My "ahead of main" conclusion compared #80's base against my **scratch clone's `origin/main`, which was a stale pre-merge snapshot** (cloned in the ~30s window before the merge, never re-fetched). Apologies for the noise. #80 will auto-retarget (e.g. to v0.5.0 once #77's feat content lands) per the update-path force-reset. --- ~~⚠️ **Spurious rolling PR — do not merge.** This branch is built on the unmerged #79 feature commits; base.ref reads main but merge_base is 297477e, mergeable. Merging would prematurely cut v0.4.1…~~ *(struck — incorrect, see above)*
forgejo-actions changed title from chore(release): v0.4.1 to chore(release): v0.5.0 2026-06-26 00:00:16 +02:00
forgejo-actions force-pushed release-prep/rolling from b418df47d6 to 3ae135c73d 2026-06-26 00:00:18 +02:00 Compare
forgejo-actions force-pushed release-prep/rolling from 3ae135c73d to 71bbb975c2 2026-06-26 00:12:32 +02:00 Compare
forgejo-actions force-pushed release-prep/rolling from 71bbb975c2 to f03c437d04
All checks were successful
release / decide + act (push) Successful in 8s
release / release (push) Successful in 0s
2026-06-26 00:33:53 +02:00
Compare
surveyor approved these changes 2026-06-26 00:39:41 +02:00
surveyor left a comment

Gate-1 — v0.5.0 rolling-release PR (closes the v0.4.0→v0.5.0 arc)

APPROVED (advisory — operator is the Gate-1/merge gate). Pinned to head f03c437d. Mechanics verified solid; one CHANGELOG-polish should-consider + one CI-gating note before the cut.

Verified at source (on live main 46b2b72)

  • VERSION = 0.5.0 — correct minor bump (#77 feat drives minor).
  • Manifest untouched — still v0.4.0 state (last_released_sha=5f4812d); the cut writes it. ✓
  • Fragments 52/77/78 consumed (deleted); sidecar added.
  • Sidecar = three short summaries (slice-5 + #77 under §Added, #78 under §Fixed) — the (B1) bifurcation working end-to-end. draft-release.sh sources the release body from the sidecar (-f && -s → present), so the v0.5.0 draft gets the concise 3-summary body, not the long CHANGELOG.
  • CHANGELOG v0.5.0 §Added/§Fixed = full long-form prose, no leaked frontmatter (the ---/summary: lines are inside #77's intentional code-fence example). ## [Unreleased] preserved above it → post-merge manifest-check passes.
  • Cut-window ancestry sound5f4812d ancestor of HEAD; git log 5f4812d..HEAD = the full v0.5.0 arc.

Should-consider before cutting — CHANGELOG double-lists #77/#78 (cosmetic, repo-history only)

The v0.5.0 CHANGELOG carries each of #77/#78 twice: the full fragment prose and a redundant one-line cc-subject bullet (- **fragments**: … (closes #77) in §Added, - **_release**: … (closes #78) in §Fixed). The raw compose pulls from both the changelog.d fragment and the conventional commit for the same change. For comparison, v0.4.0's CHANGELOG has 0 such stray bullets — it was operator-folded clean; v0.5.0 is the raw un-folded compose. The sidecar/release-notes are clean (no duplication), so this is repo-history only — but for a milestone CHANGELOG I'd:

  1. operator-fold the 2 stray bullets before cutting (matches the v0.4.0 precedent → clean v0.5.0 CHANGELOG), and
  2. file a compose-dedup follow-up so a change with both a fragment + a cc-commit doesn't double-list (removes the recurring manual-fold need — this is the same operator-fold toil #77 was partly about).

CI-gating note (not a block)

The rolling-PR head has no CI statusmanifest-check didn't trigger on it (the bot force-reset of release-prep/rolling doesn't re-fire PR CI; Forgejo anti-recursion on actions-bot pushes). I verified the prep state directly above, and manifest-check would pass (VERSION 0.5.0 ahead of the v0.4.0 tag = the documented post-prep pass state; [Unreleased] present). The real validation gate is post-merge on main — the release / decide+act + manifest-check that show green on 46b2b72 run on the cut. So the cut isn't ungated; it's gated post-merge, not pre-merge — just flagging that the rolling PR carries no pre-merge CI badge.

Watch — first live (B) cut

Merging this fires the first live exercise of #78's manifest-via-PR (B) path + #77's sidecar consumption. Per the §Branch-protection doc I just reviewed, I expect the toolkit's own auto-merge to degrade to manual (non-admin token + apply_to_admins:false + empty whitelist) → a release-toolkit/manifest-v0.5.0 PR opens for a one-off manual merge. I'll verify the cut at cut-weight: the draft (3-summary body), the manifest PR, and the degradation behaving as documented.

Clean to cut — I'd just fold the 2 CHANGELOG bullets first for a polished v0.5.0.

## Gate-1 — v0.5.0 rolling-release PR (closes the v0.4.0→v0.5.0 arc) **APPROVED** (advisory — operator is the Gate-1/merge gate). Pinned to head `f03c437d`. Mechanics verified solid; one CHANGELOG-polish should-consider + one CI-gating note before the cut. ### Verified at source (on live main `46b2b72`) - **VERSION = 0.5.0** — correct minor bump (#77 feat drives minor). - **Manifest untouched** — still v0.4.0 state (`last_released_sha=5f4812d`); the cut writes it. ✓ - **Fragments 52/77/78 consumed** (deleted); **sidecar added**. - **Sidecar = three short summaries** (slice-5 + #77 under §Added, #78 under §Fixed) — the (B1) bifurcation working end-to-end. `draft-release.sh` sources the release body from the sidecar (`-f && -s` → present), so the v0.5.0 **draft gets the concise 3-summary body**, not the long CHANGELOG. - **CHANGELOG** v0.5.0 §Added/§Fixed = full long-form prose, no leaked frontmatter (the `---`/`summary:` lines are inside #77's intentional code-fence example). `## [Unreleased]` preserved above it → post-merge manifest-check passes. - **Cut-window ancestry sound** — `5f4812d` ancestor of HEAD; `git log 5f4812d..HEAD` = the full v0.5.0 arc. ### Should-consider before cutting — CHANGELOG double-lists #77/#78 (cosmetic, repo-history only) The v0.5.0 CHANGELOG carries each of #77/#78 **twice**: the full fragment prose **and** a redundant one-line cc-subject bullet (`- **fragments**: … (closes #77)` in §Added, `- **_release**: … (closes #78)` in §Fixed). The raw compose pulls from *both* the `changelog.d` fragment and the conventional commit for the same change. For comparison, **v0.4.0's CHANGELOG has 0 such stray bullets** — it was operator-folded clean; v0.5.0 is the raw un-folded compose. The **sidecar/release-notes are clean** (no duplication), so this is repo-history only — but for a milestone CHANGELOG I'd: 1. **operator-fold the 2 stray bullets before cutting** (matches the v0.4.0 precedent → clean v0.5.0 CHANGELOG), and 2. file a **compose-dedup follow-up** so a change with both a fragment + a cc-commit doesn't double-list (removes the recurring manual-fold need — this is the same operator-fold toil #77 was partly about). ### CI-gating note (not a block) The rolling-PR head has **no CI status** — `manifest-check` didn't trigger on it (the bot force-reset of `release-prep/rolling` doesn't re-fire PR CI; Forgejo anti-recursion on actions-bot pushes). I verified the prep state directly above, and manifest-check *would* pass (VERSION 0.5.0 ahead of the v0.4.0 tag = the documented post-prep pass state; `[Unreleased]` present). The real validation gate is **post-merge on main** — the `release / decide+act` + manifest-check that show green on `46b2b72` run on the cut. So the cut isn't ungated; it's gated post-merge, not pre-merge — just flagging that the rolling PR carries no pre-merge CI badge. ### Watch — first live (B) cut Merging this fires the **first live exercise of #78's manifest-via-PR (B) path** + #77's sidecar consumption. Per the §Branch-protection doc I just reviewed, I expect the toolkit's own auto-merge to **degrade to manual** (non-admin token + `apply_to_admins:false` + empty whitelist) → a `release-toolkit/manifest-v0.5.0` PR opens for a one-off manual merge. I'll verify the cut at cut-weight: the draft (3-summary body), the manifest PR, and the degradation behaving as documented. Clean to cut — I'd just fold the 2 CHANGELOG bullets first for a polished v0.5.0.
alex merged commit f03c437d04 into main 2026-06-26 00:40:30 +02:00
alex deleted branch release-prep/rolling 2026-06-26 00:40:30 +02:00
Sign in to join this conversation.
No description provided.