Release checklist
Execute top-to-bottom. A stable release is one immutable transaction, not a draft-to-prerelease promotion.
1. Pre-tag controls
-
mainis clean andgo test ./...,go vet ./...,golangci-lint run,bash scripts/validate-docs.sh, andpython3 -m tox -e docspass. -
RELEASE_PLEASE_GITHUB_TOKENis provisioned only for Release Please in this repository. -
CI_GITHUB_TOKENis present from Doppler repository sync and can read repository Administration settings. The release workflow exposes it only toGET /repos/jbcom/radioactive-ralph/immutable-releases; missing, inaccessible, malformed, or disabled state fails the release closed. - The
Release authority preflightworkflow has passed from exact currentmain. Protected-main changes to the release authority path run it automatically; arelease_authority_preflightrepository dispatch safely re-runs default-branch code after credential rotation. It invokes the same fail-closed helper without creating a tag, release, asset, or package mutation. -
PKGS_GITHUB_TOKENcan read, create PRs in, and squash-merge checked heads injbcom/pkgs; it is not used for this repository's releases. - Repository immutable releases are enabled.
-
radioactive-ralphmain protection is strict, applies to administrators, requires PRs, linear history, conversation resolution, and all 25 GitHub-Actions-app-ID-15368contexts:Test (ubuntu-latest),Test (macos-latest),Test (windows-latest),E2E (CI-feasible),GUI (ubuntu-latest),GUI (macos-latest),Build (linux/amd64),Build (linux/arm64),Build (darwin/amd64),Build (darwin/arm64),Build (windows/amd64),Build (windows/arm64),Lint,Workflow lint,Vulnerability scan,Docs,Packaging lint,Package artifacts,Package artifacts (arm64),Package GUI (ubuntu-latest),Package GUI (macos-latest),Package GUI (macos-15-intel),Package GUI (windows-latest),Analyze (actions), andAnalyze (javascript-typescript). -
jbcom/pkgsmain requires protectedvalidateandbuild-sitechecks from GitHub Actions app ID15368.
2. Snapshot proof
goreleaser release --snapshot --clean --skip=sign,publishThe snapshot build itself is portable. The native archive/deb/rpm/installer smoke is Linux-only and must run on both Ubuntu x86_64 and Ubuntu arm64:
bash scripts/ci/smoke_goreleaser_artifacts.shOn macOS or Windows the smoke helper fails immediately with a clear platform
error; use the two native Package artifacts CI jobs for that proof.
- Five CLI archives, amd64/arm64
.deband.rpm,checksums.txt, Homebrew CLI cask, and Scoop manifest are exact. - The four native
Package GUIcontexts produce and execute both macOS DMGs, the Linux AppImage, and Windows EXE. - Actual amd64 and arm64 deb/rpm clean-install and execution proof exists.
-
radioactive_ralph --versionand--helpmatch the intended version and CLI surface.
3. Stable install surface
- Homebrew CLI:
brew tap jbcom/pkgs https://github.com/jbcom/pkgs && brew install --cask radioactive-ralph. - Homebrew GUI on both Apple Silicon and Intel:
brew install --cask radioactive-ralph-gui. - Scoop:
scoop bucket add jbcom https://github.com/jbcom/pkgs && scoop install radioactive-ralph. - Debian/Ubuntu:
sudo apt install ./radioactive-ralph_<version>_linux_<arch>.deb. - Fedora/RHEL:
sudo dnf install ./radioactive-ralph_<version>_linux_<arch>.rpm. - The curl installer and AppImage match their signed release manifests.
- winget remains generated-only. Chocolatey remains optional and can run only after the immutable GitHub release has published successfully; it is not part of the stable gate.
4. Release Please handoff
Do not create or move a release tag manually.
- Ruleset Release tags are admin-created (ID
19751997) is active, targetstag, includesrefs/tags/v*, has the creation rule, and grants onlyOrganizationAdminanalwaysbypass. - Ruleset Release tags cannot move or be deleted (ID
19752322) is active, targetstag, includesrefs/tags/v*, has update and deletion rules, and has no bypass actors. - Merging the Release Please PR creates the forced stable tag and one non-prerelease draft.
-
release-admissionbinds tag, event SHA, draft target, manifest version,origin/main, the dedicated package secret, and the live immutable-release repository setting before any publisher runs. Its built-in token iscontents: read, so no step in the job holds a write-capable credential. GitHub only exposes private draft releases to principals with push access, so the draft-state read usesCI_GITHUB_TOKEN— the same named authority that reads the immutable-release setting. Checkout usespersist-credentials: false. The command contract is enforced as an allowlist over the job's actualghinvocations (onlygh release view, and no--method/-X/field flags), not as a blocklist of literal flag spellings that reordering could evade. - A public prerelease is rejected. There is no public staging state.
5. Draft rendezvous and seal
All prepublication verification uses authenticated draft downloads. Package install steps receive no GitHub token: a preceding fetch step caches the exact PR-head manifests and draft assets, then credentials are unset before Homebrew or Scoop executes package content.
GoReleaser uploads nine CLI/native-package deliverables plus the signed consolidated
checksums.txt.Four GUI jobs upload four deliverables; one signer uploads the consolidated
gui-checksums.txtand its Sigstore bundle.package-rollback.tar.gzcontains the exact original three package files, their hashes, and original package-main OID; its workflow-identity signature verifies. A rerun reuses it and never resets “prior” to a bad already-merged main.package-manifests.tar.gzand its workflow-identity signature preserve the exact generated CLI cask, derived GUI cask, and generated Scoop bytes. Initial publication and sealed reruns both consume this archive; neither reconstructs an approximation from transient Actions artifacts.release-seal.jsonis created last and signs source/tag/tool pins plus the name, size, and SHA-256 of every other immutable asset.The exact immutable asset set is 23 assets: 13 deliverables, two checksum manifests and bundles, rollback provenance and bundle, exact package manifests and bundle, and release seal and bundle. The seal inventories all 21 assets that precede it.
Admission distinguishes
draft-unsealedfromdraft-sealed. A sealed rerun skips every clobbering build/uploader, verifies the seal signature and every byte before package mutation, then resumes from durable GitHub state. Partial or inconsistent seal state is quarantined.Verify each signature with:
cosign verify-blob <manifest> \ --bundle <manifest>.sigstore.json \ --certificate-identity "https://github.com/jbcom/radioactive-ralph/.github/workflows/release.yml@refs/tags/v<MAJ>.<MIN>.<PATCH>" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com"The atomic package PR changes exactly
Casks/radioactive-ralph.rb,Casks/radioactive-ralph-gui.rb, andbucket/radioactive-ralph.json.The package gate binds same-repository ownership,
mainbase, exact changed files, exact release URLs/hashes, exact checked head, and required workflow/app provenance.Authenticated cached Homebrew and Scoop premerge smokes pass without any package-write credential in the install/execution step.
6. Final transaction
The final transaction orders its state changes and authority reads exactly:
- squash-merge only the checked atomic package PR head;
- identify the unique winning package merge and complete the slow exact 23-asset verification;
- after that slow verifier, run a lightweight current package recheck that
requires all three target paths' latest commit to still equal the proven
winning merge OID and current
mainbytes to equal the small signedpackage-manifests.tar.gzpayload; - immediately after the lightweight package recheck, freshly require the live
immutable-release setting, source
mainversion, tag SHA, and exact draft target/state, then PATCH once withdraft=false,prerelease=false, andmake_latest=true; - treat the fresh post-PATCH release read as authoritative when the PATCH
response is absent or uncertain, accepting only the exact immutable stable
state and otherwise compensating an exact draft or quarantining ambiguity;
and require
/releases/latestto identify that release.
The immutable-release authority gate runs at tag admission, again at the start of the final transaction before any package mutation, and a third time immediately before promotion. If the third read is missing, inaccessible, malformed, or disabled after the package merge, the transaction's protected compensation restores the exact prior package manifests and leaves the draft unpublished.
- No public prerelease existed.
- The current package-main OID and the actual winning release squash-merge OID are recorded separately. Official rollback consumes the winning merge OID; its first parent is authoritative for the actual package state immediately before that merge. Signed seal-time provenance is only an integrity cross-check and never overrides ancestry.
- The release is stable, immutable, and Latest.
- A published rerun is read-only: it verifies the seal, immutable assets,
and historical atomic merge. The selected attempt must have a valid
mergedAtstrictly before the immutable releasepublished_at; equality is rejected because GitHub timestamps are second-granular. It requires Latest only while this is still the highest intended version.
7. Public observational smokes
GitHub cannot prove anonymous final release URLs before publication, and a cross-repository PR merge plus GitHub release publish cannot be one database transaction. That public-network window is unavoidable and explicit.
- Official Homebrew CLI/GUI installs and executions pass on Apple Silicon and Intel.
- Official Scoop install and execution pass.
- Anonymous curl, amd64/arm64 deb, amd64/arm64 rpm, and amd64 AppImage checks pass.
- Provider-live uses Claude Code
2.1.220and Codex0.145.0in separate jobs; provider secrets exist only on their own live invocation/auth steps, and Codex uses then destroys a temporaryCODEX_HOME. - launchd and systemd-user manual host smokes pass; native Windows
foreground supervisor/client proof and
ErrPTYUnsupportedworker refusal pass, and SCM install/start is rejected without leaving a registration, config, or process. Until a real WSL2 workflow exists, a manual WSL2 host proof owns the Linux-build provider turn andsystemd --userlifecycle.
8. Compensation and terminal versions
Before publication, any failure after package merge runs protected rollback.
Rollback derives the prior state from the unique winning exact package PR's
squash-merge first parent; signed seal-time provenance is only a cross-check.
It retries safely if strict package main advances for unrelated work. After
compensation, a rerun uses a deterministic new attempt branch built from the
sealed bytes and current package main.
After publication, assets and tag are immutable. If an official public-channel smoke fails, protected rollback removes the broken package-manager pointers and the version is terminal. Record the failure prominently and issue a new patch immediately. Never claim that a same-tag rerun repairs the public release.
Do not move/delete the tag, mutate assets, turn the release into a prerelease,
or use Contents API DELETE calls for package rollback.
9. Invariants
- Release Please remains manifest-mode, force-tagged, and draft.
- The only public transition is draft to immutable stable/latest.
checksums.txt,gui-checksums.txt, rollback provenance, and the release seal remain consolidated workflow-identity-signed artifacts.- Package creation is one atomic PR; package merge is not release publication.
- Current-repository release reads and writes use the built-in token.
CI_GITHUB_TOKENis command-scoped only to immutable-release settings reads that requireAdministration: read. Cross-repository package operations use onlyPKGS_GITHUB_TOKEN. Release Please uses onlyRELEASE_PLEASE_GITHUB_TOKEN. - The release-authority preflight runs only for protected-
mainpushes to its authority path or therelease_authority_preflightrepository-dispatch event. GitHub resolves repository dispatches to default-branch code; the job also rejects every SHA except exact currentmainand performs no release mutation. - Fyne stays pinned at
v1.7.2, GoReleaser atv2.17.0, Claude Code at2.1.220, and Codex at0.145.0.
