Pulse/docs/releases/V6_PRERELEASE_RUNBOOK.md
2026-04-23 22:16:38 +01:00

234 lines
9.2 KiB
Markdown

# Pulse v6 Prerelease Runbook
This runbook captures the branch-specific operational path that was used while
`main` continued to serve v5 releases during the v6 prerelease period.
Canonical customer-channel and promotion rules now live in
`docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`.
Current release-branch authority lives in
`docs/release-control/control_plane.json`.
If this historical runbook and the release-control policy disagree, the
release-control policy wins.
## Branch Model (Current)
- `main`: v5 stable (current public/stable line)
- `pulse/v6-release`: active v6 prerelease and stable release line until an explicit
post-GA branch cutover is governed
Do not move `main` to v6 during prerelease.
## Enforced Workflow Policy
Release workflows now enforce branch/tag lineage rules:
- `Pulse Release Pipeline` (`create-release.yml`)
- Resolves stable versus prerelease branch requirements from
`docs/release-control/control_plane.json`.
- For the current v6 profile, both stable and prerelease releases dispatch
from `pulse/v6-release`.
- `publish-docker.yml`, `promote-floating-tags.yml`, `publish-helm-chart.yml`,
and `update-demo-server.yml`
- Validate the release tag commit is reachable from the governed branch for
that version instead of assuming `main`.
- `update-demo-server.yml`
- Routes stable tags to the stable demo environment and prerelease tags to
the separate v6 preview demo environment.
- The selected tag must still be reachable from the governed branch for that
version.
This prevents accidental cross-line releases from non-governed branches even if
the stable branch changes later.
## Important Scope Note
The Pulse release workflow in this repo (`.github/workflows/create-release.yml`) builds from the checked-out `Pulse` ref and runs `./scripts/build-release.sh`, which builds `./cmd/pulse`.
It does not automatically check out or build `pulse-enterprise`.
That means public `pulse-v...` release archives are OSS runtime artifacts. They must not be
described as including Pulse Pro runtime features unless a separate Pro package has been built
from `pulse-enterprise` against the same Pulse ref and version.
Paid-user GA is blocked until the Pro release artifacts are built and wired into the paid
install/upgrade path. The current Pro packaging path lives in `pulse-enterprise`:
- `.github/workflows/build-pro-release.yml`
- `scripts/build-pro-release.sh`
The paid-user promise is only satisfied when paid customers are directed to `pulse-pro-v...`
artifacts, or to an explicitly verified paid container image, rather than the public OSS
`pulse-v...` archives.
## Versioning Rules
- v5 stable examples: `5.1.14`
- v6 prerelease examples: `6.0.0-rc.1`, `6.0.0-rc.2`
- v6 GA example: `6.0.0`
The workflow auto-marks `-rc.N`/`-alpha.N`/`-beta.N` as prerelease.
## Preconditions for Each RC
1. `pulse/v6-release` is pushed and green in CI.
2. `VERSION` file in `pulse/v6-release` exactly matches the release input version.
3. The current RC release packet is prepared and internally linked:
- release notes
- changelog
- operator support pack
- `docs/RELEASE_NOTES.md` points at the current in-repo draft packet
4. `PULSE_LICENSE_PUBLIC_KEY` secret is present in GitHub Actions.
5. For any build after `v6.0.0-rc.2`, operators know the update signer changed.
Hosts pinned to the historical `rc.2` trust root must not assume unattended
continuity into later prerelease or GA artifacts; use a manual reinstall or
other explicit trust-migration path before testing those newer packets.
6. For paid-user GA, run the `pulse-enterprise` Pro release workflow against the
same Pulse ref/version, verify `pulse-pro-v...` archives exist, verify
`bin/pulse --version` identifies `Pulse Pro (Enterprise)`, and confirm the paid
install/upgrade docs point paid customers to the Pro artifacts or verified paid
container image.
## RC Release Steps
1. Update version on `pulse/v6-release`:
```bash
export RC_VERSION="6.0.0-rc.2"
git checkout pulse/v6-release
git pull --ff-only
printf '%s\n' "$RC_VERSION" > VERSION
git add VERSION
git commit -m "chore(release): bump version to ${RC_VERSION}"
git push origin pulse/v6-release
```
2. Optional preflight dry run:
- Run workflow: `Release Dry Run`
- Ref: `pulse/v6-release`
- Inputs:
- `version`: `RC_VERSION`
- optional `note`
3. Create draft prerelease:
- Run workflow: `Pulse Release Pipeline`
- Ref: `pulse/v6-release`
- Inputs:
- `version`: `RC_VERSION`
- `release_notes`: markdown text from the current release-notes packet
- `draft_only`: `true`
- Keep the current release-notes, changelog, and operator-support packet in
sync. Do not update only one of them and treat the packet as ready.
4. Validate draft outputs:
- Confirm assets exist and checksums match.
- Confirm GitHub release is marked prerelease.
- Smoke install on a test host/container.
5. Publish prerelease:
- Re-run `Pulse Release Pipeline` on `pulse/v6-release`
- Same `version` and release-notes packet
- `draft_only`: `false`
- Existing unpublished draft releases for the same tag are updated in place
and their tag is retargeted to the current governed `pulse/v6-release`
head automatically. Do not delete the tag manually just to retry publish.
- The release workflow dispatches `update-demo-server.yml` against the
`preview-v6` demo target automatically.
- Keep the public stable demo on v5/stable; prereleases must land only on
the separate preview demo runtime.
6. Canary rollout:
- Upgrade a small user subset first.
- Collect regressions, fix on `pulse/v6-release`, then cut `rc.2`/`rc.3` as needed.
## Keep v5 Stable During v6 RC
- Continue v5 patch releases from `main` as normal.
- Do not merge `pulse/v6-release` into `main` during prerelease.
- Keep v5 and v6 changelogs/release notes separate.
- Do not rewrite shipped RC notes in place. Each RC should get its own draft or
published release-notes packet so `rc.1`, `rc.2`, and later prerelease
support context remain historically accurate.
## GA Cutover (Only After RC Confidence)
Do this only when v6 is proven stable in production-like usage.
1. Create v5 long-tail branch from current `main`:
```bash
git checkout main
git pull --ff-only
git checkout -b pulse/v5-maintenance
git push -u origin pulse/v5-maintenance
```
2. Keep the governed v6 release line on `pulse/v6-release` for GA:
```bash
git checkout pulse/v6-release
git pull --ff-only
```
3. Release `6.0.0` from `pulse/v6-release` using `Pulse Release Pipeline`.
Before the real GA publish, run `./scripts/trigger-release-dry-run.sh 6.0.0`
from `pulse/v6-release`. That helper validates the default-branch workflow-dispatch
contract before calling GitHub so stale `main` workflow inputs fail locally
instead of returning an opaque 422 from `gh workflow run`.
The governed `Release Dry Run` must still carry:
- `version`: `6.0.0`
- `promoted_from_tag`: exact prerelease tag being promoted
- `rollback_version`: prior stable
- `ga_date`: exact published v6 GA date
- `v5_eos_date`: exact published v5 end-of-support date
- optional `hotfix_exception` and `hotfix_reason`
After the run passes, materialize the governed dated rehearsal record with
`python3 scripts/release_control/record_rc_to_ga_rehearsal.py --run-id <run-id>`.
If `--output` is omitted, that recorder writes to
`docs/release-control/v6/internal/records/rc-to-ga-promotion-readiness-rehearsal-<record-date>.md`.
Attach that record, the `rc-to-ga-rehearsal-summary` artifact, and the run URL
to the release ticket, and confirm the artifact carries the canonical promotion
metadata envelope for that candidate: candidate stable tag, promotion channel,
promoted prerelease tag, rollback target, exact rollback command, planned GA date,
and planned v5 end-of-support date.
4. Publish the exact v6 GA date and v5 end-of-support date in the GA release
notice using
`docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` as the canonical
policy.
5. Continue critical v5 fixes from `pulse/v5-maintenance` only.
- The support window lasts 90 calendar days from v6 GA.
- Only critical security issues, critical correctness/data-loss issues,
installer or updater failures, licensing or billing blockers, and safe
migration blockers are eligible during that window.
- After that window, v5 is unsupported.
6. Treat any future move of stable v6 releases away from `pulse/v6-release` as a
separate post-GA governance change; do not assume an automatic cutover to
`main`.
## Rollback Strategy
If an RC is bad:
1. Do not promote to GA.
2. Keep fixing on `pulse/v6-release`.
3. Cut next RC.
4. Keep v5 users on `main` stable releases.
If GA has a severe regression:
1. Patch quickly on `pulse/v6-release` (v6.0.1), or
2. Advise affected users to hold at prior stable while fix ships.
3. Continue v5 emergency fixes from `pulse/v5-maintenance` only if the
published maintenance-only window is still active or I explicitly announce
an exception.
## Minimal Per-Release Checklist
1. Version file matches workflow input.
2. CI green on release ref.
3. Draft release validated.
4. Checksums and assets verified.
5. Canary cohort upgraded successfully.
6. Rollback note prepared before publish.