## Summary
Redesign the permanent Desktop release flow so unrelated merges to
`main` cannot invalidate an already reviewed, green release candidate.
- Tag the immutable, API-confirmed release PR head instead of its later
squash commit.
- Treat the merged PR—including an authorized owner/admin bypass—as
publication authorization, while requiring trusted check evidence that
was complete at merge time.
- Make tag creation idempotent and collision-safe: an existing tag
succeeds only at the exact candidate SHA, and create races refetch
before accepting equality.
- Replace ancestry-based previous-release discovery with a validated
metadata ledger for side-history candidate tags.
- Compute the next release from the prior frozen base to the new frozen
base, excluding only the prior release squash SHA so unrelated commits
remain in the changelog.
- Preserve schema-1 production-tag migration and reject malformed
metadata or equal/decreasing versions.
- Update operator documentation for the normal squash-merge workflow.
This is the reusable release process for `0.5.6` onward, not the retired
one-shot `0.5.5` recovery path.
### Invariants covered
- Candidate creation → unrelated `main` merge → authorized squash merge
→ immutable candidate tag.
- Trusted producer IDs and merge-time completion timestamps; DCO's
bounded post-merge exception remains isolated.
- Missing/spoofed checks, tampered candidates, ambiguous PR
associations, conflicting tags, and equal/decreasing versions fail
closed.
- Same-SHA retries succeed; different-SHA collisions fail.
- Legacy schema-1 tag-on-main migration and schema-2 side-history
accounting both preserve the correct next-release changelog.
### Related issue
N/A — follows the Desktop release failures in #4788 and #4800 and the
recovery revert in #4808.
### Testing
At clean commit `6a91fbed8147a48cf174997de0c3e4cb2fb26474`:
- `scripts/test-desktop-release-candidate.sh`
- `scripts/test-release-ref-contract.sh`
Both focused suites passed with HEAD unchanged. Princess Donut cleared
the security/provenance surface, including the hostile merge-time
timestamp cases. Mongo cleared the side-history ledger, migration,
version-order, documentation, and contract-test surface.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- escape the Markdown backticks around `main` in the desktop release PR
body
- prevent the shell from executing `main` as command substitution
- lock the heredoc contract into the release-ref test
## Verification
- `scripts/test-release-ref-contract.sh`
- `bash -n scripts/prepare-desktop-release.sh
scripts/test-release-ref-contract.sh`
- `git diff --check origin/main...HEAD`
This is a follow-up to the cosmetic PR-body issue observed on #3972. It
does not modify that frozen release candidate.
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- validate desktop release candidates before merge and keep the
repository squash-only
- tag the squash commit only after proving frozen-base parent and
complete-tree identity with the validated PR head
- accept either an exact-head approval or the durable Default-ruleset
bypass record as release authorization
- remove the unusable App-backed preparation workflow; retain `just
release-desktop`
## Ruleset follow-up
After this PR merges, update Default ruleset `13596885` to:
- enable strict required status checks
- dismiss stale reviews on push and require approval after the last push
- require the integration-bound `Desktop Release Candidate` check
The next desktop release should be cut only after that settings update.
## Verification
At commit `d8c254db427eedbcffac1a6e078e90d1d0f5e151` with a clean
worktree:
- `scripts/test-release-ref-contract.sh`
- `scripts/test-desktop-release-candidate.sh`
- `bash -n scripts/verify-desktop-release-merge.sh
scripts/prepare-desktop-release.sh scripts/test-release-ref-contract.sh`
- `git diff --check`
The bypass test fixture is the captured rule-suite shape from real
squash merge PR #2864 / suite `3520068134`.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
## Summary
- add a manual desktop release preparer that regenerates one
version-only candidate from current `origin/main`
- validate deterministic complete changelog accounting, candidate
authorship, allowed files, exact-head approval, required checks, and
two-parent merge topology before tagging the reviewed candidate
- move desktop tags/releases from `v*` to `desktop-v*` while preserving
relay, chart, push-chart, and mobile behavior
- stage all four platform outputs in Actions artifacts and grant GitHub
release write access only to one final all-platform-gated publisher
- publish the versioned release only after complete artifact assembly;
update stable `latest.json` last; never promote prereleases or published
rebuild outputs
## Safety properties
- desktop tags point to the reviewed candidate SHA, not the merge commit
- release builds remain tag-bound and reverify tag == checked-out HEAD
- one final writer fails closed on artifact basename collisions
- per-tag concurrency serializes publication without cancellation
- published reruns do not replace immutable versioned assets or promote
signatures from a rebuild
- candidate branches use an explicit remote OID lease when regenerated
## Validation
- `scripts/test-desktop-release-candidate.sh`
- `scripts/test-release-ref-contract.sh`
- `scripts/test-mobile-release-contract.sh`
- changed workflow YAML parsing (Ruby Psych)
- changed shell syntax (`bash -n`)
- `git diff --check`
- push hooks: branch-skew, Rust workspace tests (1,853 passed), desktop
Tauri tests (3 passed)
## Coordinated companion
- squareup/buzz-releases#79 updates the manually entered desktop
source-tag contract to stable-only `desktop-v*`
- merge the private contract companion before the first namespaced
desktop release
## Rollout blockers (no settings changed here)
Before the first candidate/release:
1. enable merge commits in repository settings
2. allow `merge` in ruleset `13596885`
3. require approval after the last push in ruleset `13596885`
4. include `refs/tags/desktop-v*` explicitly in release ruleset
`14378754`
5. prove the non-publishing candidate/merge/tag/artifact validation path
before any production release
Do not test the old workflow with a prerelease: it can still mutate the
production rolling updater release.
---------
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>