From cb4147301870f7fa0b0b528d91fc97406ce70d46 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 25 Mar 2026 11:08:05 +0000 Subject: [PATCH] Rename promotion RC wording to prerelease --- .github/workflows/create-release.yml | 10 ++--- .github/workflows/promote-floating-tags.yml | 4 +- .github/workflows/publish-docker.yml | 4 +- .github/workflows/release-dry-run.yml | 8 ++-- docs/release-control/v6/README.md | 6 +-- .../v6/internal/PRE_RELEASE_CHECKLIST.md | 6 +-- .../internal/RC_TO_GA_REHEARSAL_TEMPLATE.md | 12 ++--- .../v6/internal/SOURCE_OF_TRUTH.md | 4 +- ...-promotion-readiness-blocked-2026-03-13.md | 39 ++++++++-------- .../subsystems/deployment-installability.md | 12 ++++- docs/releases/V6_PRERELEASE_RUNBOOK.md | 4 +- .../canonical_development_protocol_test.go | 4 +- .../record_rc_to_ga_blocked.py | 42 +++++++++--------- .../release_promotion_policy_support.py | 6 +-- .../release_promotion_policy_support_test.py | 4 +- .../release_promotion_policy_test.py | 44 ++++++++++--------- .../resolve_release_promotion.py | 8 ++-- scripts/trigger-release-dry-run.sh | 10 ++--- scripts/trigger-release.sh | 10 ++--- 19 files changed, 126 insertions(+), 111 deletions(-) diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 5a86e7848..0fd729149 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -1,5 +1,5 @@ name: Pulse Release Pipeline -# Optimized: parallel jobs, fast RC path +# Optimized: parallel jobs, fast prerelease path on: workflow_dispatch: @@ -13,7 +13,7 @@ on: required: true type: string promoted_from_tag: - description: 'Stable only: RC tag being promoted (for example 6.0.0-rc.2)' + description: 'Stable only: prerelease tag being promoted (for example 6.0.0-rc.2)' required: false type: string rollback_version: @@ -29,7 +29,7 @@ on: required: false type: string hotfix_exception: - description: 'Stable only: bypass the 72-hour RC soak for urgent customer harm' + description: 'Stable only: bypass the 72-hour prerelease soak for urgent customer harm' required: false type: boolean default: false @@ -503,9 +503,9 @@ jobs: echo "- Promotion channel: ${{ needs.prepare.outputs.is_prerelease == 'true' && 'rc' || 'stable' }}" echo "- Candidate stable tag: ${{ needs.prepare.outputs.tag }}" if [ -n "${{ needs.prepare.outputs.promoted_from_tag }}" ]; then - echo "- Promoted RC tag: ${{ needs.prepare.outputs.promoted_from_tag }}" + echo "- Promoted prerelease tag: ${{ needs.prepare.outputs.promoted_from_tag }}" else - echo "- Promoted RC tag: n/a" + echo "- Promoted prerelease tag: n/a" fi echo "- Rollback target: ${{ needs.prepare.outputs.rollback_tag }}" echo "- Rollback command: \`${{ needs.prepare.outputs.rollback_command }}\`" diff --git a/.github/workflows/promote-floating-tags.yml b/.github/workflows/promote-floating-tags.yml index 58a62921c..7b03051f0 100644 --- a/.github/workflows/promote-floating-tags.yml +++ b/.github/workflows/promote-floating-tags.yml @@ -108,7 +108,7 @@ jobs: BASE_VERSION="${BASE_VERSION%%-*}" mapfile -t RC_TAGS < <(git tag -l "v${BASE_VERSION}-rc.*" --sort=-version:refname) if [ "${#RC_TAGS[@]}" -eq 0 ]; then - echo "::error::Stable tag ${TAG} has no matching RC tags for base version ${BASE_VERSION}." + echo "::error::Stable tag ${TAG} has no matching prerelease tags for base version ${BASE_VERSION}." exit 1 fi @@ -122,7 +122,7 @@ jobs: done if [ -z "$MATCHED_RC" ]; then - echo "::error::Stable tag ${TAG} does not descend from any matching RC tag for base version ${BASE_VERSION}." + echo "::error::Stable tag ${TAG} does not descend from any matching prerelease tag for base version ${BASE_VERSION}." exit 1 fi diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index 77945327d..b91fc1960 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -80,7 +80,7 @@ jobs: BASE_VERSION="${BASE_VERSION%%-*}" mapfile -t RC_TAGS < <(git tag -l "v${BASE_VERSION}-rc.*" --sort=-version:refname) if [ "${#RC_TAGS[@]}" -eq 0 ]; then - echo "::error::Stable tag ${TAG} has no matching RC tags for base version ${BASE_VERSION}." + echo "::error::Stable tag ${TAG} has no matching prerelease tags for base version ${BASE_VERSION}." exit 1 fi @@ -94,7 +94,7 @@ jobs: done if [ -z "$MATCHED_RC" ]; then - echo "::error::Stable tag ${TAG} does not descend from any matching RC tag for base version ${BASE_VERSION}." + echo "::error::Stable tag ${TAG} does not descend from any matching prerelease tag for base version ${BASE_VERSION}." exit 1 fi diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index 078910ab0..0bb72fe87 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -8,7 +8,7 @@ on: required: false type: string promoted_from_tag: - description: 'Stable rehearsal only: RC tag being promoted (for example v6.0.0-rc.2)' + description: 'Stable rehearsal only: prerelease tag being promoted (for example v6.0.0-rc.2)' required: false type: string rollback_version: @@ -24,7 +24,7 @@ on: required: false type: string hotfix_exception: - description: 'Stable rehearsal only: bypass 72-hour RC soak for urgent customer harm' + description: 'Stable rehearsal only: bypass 72-hour prerelease soak for urgent customer harm' required: false type: boolean default: false @@ -256,7 +256,7 @@ jobs: SUMMARY_FILE="release-dry-run/rc-to-ga-rehearsal-summary.md" RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" { - echo "# RC-to-GA Rehearsal Summary" + echo "# Prerelease-to-GA Rehearsal Summary" echo "" echo "- Workflow run: ${RUN_URL}" echo "- Branch: ${GITHUB_REF_NAME}" @@ -264,7 +264,7 @@ jobs: echo "- Candidate stable tag: ${{ steps.rehearsal.outputs.tag }}" echo "- Promotion channel: ${{ steps.rehearsal.outputs.is_prerelease == 'true' && 'rc' || 'stable' }}" if [ -n "${{ steps.rehearsal.outputs.promoted_from_tag }}" ]; then - echo "- Promoted RC tag: ${{ steps.rehearsal.outputs.promoted_from_tag }}" + echo "- Promoted prerelease tag: ${{ steps.rehearsal.outputs.promoted_from_tag }}" fi if [ -n "${{ steps.rehearsal.outputs.rollback_tag }}" ]; then echo "- Rollback target: ${{ steps.rehearsal.outputs.rollback_tag }}" diff --git a/docs/release-control/v6/README.md b/docs/release-control/v6/README.md index 1148f4af5..6f2deb9c3 100644 --- a/docs/release-control/v6/README.md +++ b/docs/release-control/v6/README.md @@ -14,7 +14,7 @@ The evergreen control-plane files live one level up: 1. `../CONTROL_PLANE.md` (evergreen governance, active-profile selection, and active-target rules) 2. `../control_plane.json` (machine-readable active profile and active target) 3. `internal/SOURCE_OF_TRUTH.md` (stable human governance, readiness-assertion design rules, and locked decisions) -4. `internal/RELEASE_PROMOTION_POLICY.md` (canonical stable-versus-RC promotion rules, rollout criteria, and rollback expectations) +4. `internal/RELEASE_PROMOTION_POLICY.md` (canonical stable-versus-prerelease promotion rules, rollout criteria, and rollback expectations) 5. `internal/status.json` (live lane state, coverage-gap discovery records, readiness derivation rules, the active readiness assertion catalog, lane-to-subsystem ownership, structured evidence references, typed lane/subsystem decision records, and canonical ordered lists) 6. `status.schema.json` (machine-readable contract for the `status.json` shape) 7. `internal/subsystems/registry.json` (machine-readable subsystem ownership, explicit shared-ownership exceptions, and proof routing) @@ -22,7 +22,7 @@ The evergreen control-plane files live one level up: `status.json` reporting every lane as `target-met` means the tracked v6 repo-hardening work is at target. It does not, by itself, mean Pulse v6 is -ready to cut an RC or approve stable/GA while phase-blocking +ready to cut a prerelease or approve stable/GA while phase-blocking `readiness_assertions`, `open_decisions`, or `release_gates` remain unresolved. Use `python3 scripts/release_control/status_audit.py --pretty` for the current derived `repo_ready`, `rc_ready`, and `release_ready` summary. @@ -62,7 +62,7 @@ Supporting governance file: - `CONSOLIDATION_MAP.md` (legacy-doc demotion and archival map) - `RETIREMENT_AUDIT_2026-02-27.md` (file-by-file audited retirement decisions) - `internal/CANONICAL_DEVELOPMENT_PROTOCOL.md` (canonical subsystem development protocol) -- `internal/RELEASE_PROMOTION_POLICY.md` (customer-facing release-train contract for `stable` versus `rc`) +- `internal/RELEASE_PROMOTION_POLICY.md` (customer-facing release-train contract for `stable` versus the prerelease `rc` channel) - `internal/HIGH_RISK_RELEASE_VERIFICATION_MATRIX.md` (manual verification runbook for trust-critical release gates) - `internal/RC_TO_GA_REHEARSAL_TEMPLATE.md` (human record template for the non-publish GA rehearsal run) - `internal/subsystems/*.md` (per-subsystem contracts: truth, shared boundaries, extension points, forbidden paths, completion obligations) diff --git a/docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md b/docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md index a3ebb5abb..3cabce78a 100644 --- a/docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md +++ b/docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md @@ -20,14 +20,14 @@ Use this as the final gate before cutting a Pulse v6 pre-release. - The remaining release-ready blocker is `rc-to-ga-promotion-readiness`, which stays blocked until a later stable `6.0.0` candidate completes a matching `Release Dry Run` rehearsal with the canonical promotion artifact envelope: - candidate stable tag, promotion channel, promoted RC tag, rollback target, + candidate stable tag, promotion channel, promoted prerelease tag, rollback target, exact rollback command, exact GA date, and exact v5 end-of-support inputs. - Mobile is in scope for the release and now has targeted readiness coverage in `pulse-mobile`. - High-risk release confidence now lives in `docs/release-control/v6/internal/HIGH_RISK_RELEASE_VERIFICATION_MATRIX.md` and should be cleared alongside this checklist. ## Promotion Policy - [ ] Record the previous stable tag and exact rollback pin command before publishing a new RC or stable release. -- [ ] For the GA/stable candidate, confirm the release pipeline has already been exercised on a real RC tag, not only linted or YAML-parsed. +- [ ] For the GA/stable candidate, confirm the release pipeline has already been exercised on a real prerelease tag, not only linted or YAML-parsed. - [ ] For stable promotion, confirm the candidate commit has already shipped on `rc`. - [ ] For stable promotion, confirm the chosen `promoted_from_tag` is a prerelease that was actually published through the governed RC path, not an accidental git tag. - [ ] For stable promotion, confirm the RC soak window is at least 72 hours or document the hotfix exception explicitly. @@ -35,7 +35,7 @@ Use this as the final gate before cutting a Pulse v6 pre-release. - [ ] For GA/stable promotion, confirm `V5_MAINTENANCE_SUPPORT_POLICY.md` is still the intended policy and replace any placeholder GA notice dates with the exact v6 GA date and exact v5 end-of-support date that will ship with the announcement. - [ ] For GA/stable promotion, confirm the default-branch copy of `.github/workflows/release-dry-run.yml` already accepts the governed stable rehearsal metadata envelope (`promoted_from_tag`, `rollback_version`, `ga_date`, `v5_eos_date`) through `workflow_dispatch`, because GitHub validates dispatch inputs against the default branch even when dispatching `pulse/v6-release`. - [ ] For GA/stable promotion, confirm the release rehearsal and publish workflows both derive the governed release branch from release-control metadata instead of hardcoding a branch name inline. -- [ ] For GA/stable promotion, attach a `Release Dry Run` run URL and `rc-to-ga-rehearsal-summary` artifact to the release ticket, and confirm that artifact records the canonical promotion metadata envelope for that candidate: candidate stable tag, promotion channel, promoted RC tag, rollback target, exact rollback command, planned GA date, and planned v5 end-of-support date. +- [ ] For GA/stable promotion, attach a `Release Dry Run` run URL and `rc-to-ga-rehearsal-summary` artifact to the release ticket, and confirm that artifact records 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. ## Scope - [x] Confirm whether there is a separate mobile app codebase. diff --git a/docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md b/docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md index eb8aa6fbf..526ff4e4b 100644 --- a/docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md +++ b/docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md @@ -1,4 +1,4 @@ -# Pulse v6 RC-to-GA Rehearsal Record +# Pulse v6 Prerelease-to-GA Rehearsal Record Use this template to capture the human-side evidence for `rc-to-ga-promotion-readiness` after running the `Release Dry Run` workflow. @@ -11,13 +11,13 @@ The matching GitHub Actions artifact should be the machine-generated `rc-to-ga-rehearsal-summary`. Treat that artifact as the machine-owned source for the candidate stable tag, -promotion channel, promoted RC tag, rollback target, exact rollback command, +promotion channel, promoted prerelease tag, rollback target, exact rollback command, and planned GA/EOS dates. Only override those values in the human record if the operator is correcting a verified artifact mismatch. The generator should fail closed if the artifact omits any of that promotion metadata. Do not repair a malformed artifact by hand-writing the missing -candidate tag, promotion channel, promoted RC tag, rollback target, rollback +candidate tag, promotion channel, promoted prerelease tag, rollback target, rollback command, or GA/EOS dates into the record. ## Required Fields @@ -27,10 +27,10 @@ command, or GA/EOS dates into the record. 3. Version under rehearsal: 4. Candidate stable tag: 5. Promotion channel: -6. Promoted RC tag: +6. Promoted prerelease tag: 7. Current rollback target: 8. Exact rollback or reinstall command: -9. RC soak hours at rehearsal time: +9. Prerelease soak hours at rehearsal time: 10. Exact GA date to publish with GA: 11. v5 end-of-support date to publish with GA: 12. Result: @@ -42,7 +42,7 @@ command, or GA/EOS dates into the record. publication. 3. Confirm no manual input was surprising or ambiguous during the run. 4. Confirm the artifact-owned candidate stable tag, promotion channel, - promoted RC tag, rollback target, exact rollback command, planned GA date, + promoted prerelease tag, rollback target, exact rollback command, planned GA date, and planned v5 end-of-support date match the intended publish notice. 5. Record any follow-up issue that must be fixed before the real promotion. 6. Link this record and the matching artifact from the release ticket before diff --git a/docs/release-control/v6/internal/SOURCE_OF_TRUTH.md b/docs/release-control/v6/internal/SOURCE_OF_TRUTH.md index 3d9525eae..ba3005c8c 100644 --- a/docs/release-control/v6/internal/SOURCE_OF_TRUTH.md +++ b/docs/release-control/v6/internal/SOURCE_OF_TRUTH.md @@ -79,7 +79,7 @@ This file must not contain: Per-subsystem contracts: truth, extension points, forbidden paths, and completion obligations. 11. `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md` - Canonical stable-versus-RC promotion rules, rollout criteria, and rollback + Canonical stable-versus-prerelease promotion rules, rollout criteria, and rollback expectations for v6 and later release lines. 12. `docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` Canonical v5 maintenance-only support policy, release-line rules, and GA @@ -309,7 +309,7 @@ Assertion design rules: header chrome, or section treatment without explicit justification. 13. Do not keep polishing strong lanes while weak lanes remain behind. 14. Do not treat `status.json` lane scores reaching target as sufficient release approval by themselves; open operational decisions, machine-derived unresolved readiness assertions, and unresolved release gates still apply. -15. Do not promote v6 to stable or GA without an exercised RC, a real +15. Do not promote v6 to stable or GA without an exercised prerelease, a real release-pipeline proof run, a recorded rollback target plus exact reinstall command, and a written v5 maintenance-only support policy. 16. Do not declare a lane or blocker complete just because the first passing diff --git a/docs/release-control/v6/internal/records/rc-to-ga-promotion-readiness-blocked-2026-03-13.md b/docs/release-control/v6/internal/records/rc-to-ga-promotion-readiness-blocked-2026-03-13.md index 3d195181b..ba952fd10 100644 --- a/docs/release-control/v6/internal/records/rc-to-ga-promotion-readiness-blocked-2026-03-13.md +++ b/docs/release-control/v6/internal/records/rc-to-ga-promotion-readiness-blocked-2026-03-13.md @@ -1,4 +1,4 @@ -# RC-to-GA Promotion Readiness Blocked Record +# Prerelease-to-GA Promotion Readiness Blocked Record - Date: `2026-03-13` - Gate: `rc-to-ga-promotion-readiness` @@ -6,9 +6,9 @@ ## Blocking Facts -1. No Pulse v6 RC has shipped yet. +1. No Pulse v6 prerelease has shipped yet. 2. The repository contains accidental prerelease git tag history (`v6.0.0-rc.1`), - but those tags were never published and do not count as shipped RC lineage. + but those tags were never published and do not count as shipped prerelease lineage. 3. GitHub still validates `Release Dry Run` workflow dispatch inputs against the default branch `main`, whose current workflow contract does not accept the governed stable rehearsal metadata envelope (`promoted_from_tag`, @@ -21,30 +21,31 @@ 6. The active local `pulse/v6-release` branch currently reports `VERSION=6.0.0-rc.1`, so the working line is still prerelease and there is not yet a governed local stable `6.0.0` candidate. -7. There is still no governed `RC-to-GA Rehearsal Record` proving a successful +7. There is still no governed `Prerelease-to-GA Rehearsal Record` proving a successful non-publish `Release Dry Run` for the eventual stable `6.0.0` candidate. 8. `docs/releases/RELEASE_NOTES_v6.md` and - `docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` now carry the - currently proposed exact dates for the eventual GA notice: - - `v6` GA date: `2026-03-24` - - `v5` end-of-support date: `2026-06-22` + `docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` still leave the + GA announcement dates as placeholders because no real prerelease lineage or GA-ready + rehearsal has locked them yet: + - `v6` GA date placeholder: `[v6-ga-date]` + - `v5` end-of-support placeholder: `[v5-eos-date]` 9. There is still no governed `Release Dry Run` artifact or rehearsal record exercising stable inputs for: - `version=6.0.0` - - no governed `promoted_from_tag` exists yet because no RC has shipped + - no governed `promoted_from_tag` exists yet because no prerelease has shipped - the artifact-owned candidate stable tag for that rehearsal - the artifact-owned promotion channel for that rehearsal - - the artifact-owned promoted RC tag for that rehearsal + - the artifact-owned promoted prerelease tag for that rehearsal - the artifact-owned rollback target for that stable candidate - - `ga_date=2026-03-24` + - no exact `ga_date` is locked yet because the GA notice is still pending + - no exact `v5_eos_date` is locked yet because the GA notice is still pending - an explicit `rollback_version` - the exact derived rollback command that artifact will publish - - `v5_eos_date=2026-06-22` ## Why The Gate Cannot Be Cleared Yet The blocker is no longer missing governance text. The remaining problem is that -the control plane still treats v6 as an RC-stabilization line, the working +the control plane still treats v6 as the prerelease-stabilization line, the working version is still prerelease (`6.0.0-rc.1`), and there is still no exercised `Release Dry Run` record proving the eventual stable `6.0.0` candidate is ready for GA-style promotion. Until that rehearsal exists, stable @@ -60,24 +61,24 @@ users would still be the first real cohort for the final promotion path. 3. Land the canonical `.github/workflows/release-dry-run.yml` workflow-dispatch input contract on the default branch `main` so GitHub accepts the governed stable rehearsal metadata envelope when dispatching from `pulse/v6-release`. -4. Ship the first real RC through the governed prerelease release path and record +4. Ship the first real prerelease through the governed prerelease release path and record its exact published prerelease tag plus rollback target and exact derived rollback command. -5. Run `Release Dry Run` from `pulse/v6-release` using that published RC as +5. Run `Release Dry Run` from `pulse/v6-release` using that published prerelease as `promoted_from_tag` with: - `version=6.0.0` - an artifact-owned candidate stable tag matching that rehearsal - an artifact-owned promotion channel matching that rehearsal - - an artifact-owned promoted RC tag matching that rehearsal + - an artifact-owned promoted prerelease tag matching that rehearsal - an artifact-owned rollback target for the stable candidate - the exact planned GA and v5 end-of-support dates for the publish notice - - `ga_date=2026-03-24` + - an explicit `ga_date` chosen for that rehearsal - an explicit stable `rollback_version` - the exact derived rollback command that artifact will publish - - `v5_eos_date=2026-06-22` + - an explicit `v5_eos_date` chosen for that rehearsal 6. Capture the `rc-to-ga-rehearsal-summary` artifact and run URL. 7. Materialize the final rehearsal record from that artifact without - hand-repairing any missing candidate tag, promoted RC tag, rollback + hand-repairing any missing candidate tag, promoted prerelease tag, rollback target, rollback command, or GA/EOS metadata. 8. Change the gate from `blocked` only if the rehearsal passes and the rollout inputs remain explicit. diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 108d77590..b3faeda88 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -40,6 +40,10 @@ server-side update execution surfaces. 18. `scripts/dev-launchd-setup.sh` 19. `scripts/dev-launchd-wrapper.sh` 20. `scripts/com.pulse.hot-dev.plist.template` +21. `.github/workflows/create-release.yml` +22. `.github/workflows/release-dry-run.yml` +23. `.github/workflows/publish-docker.yml` +24. `.github/workflows/promote-floating-tags.yml` ## Shared Boundaries @@ -55,6 +59,7 @@ server-side update execution surfaces. 3. Add or change shell installer, Windows installer, container-agent installer, or auto-update script behavior through `scripts/install.sh`, `scripts/install.ps1`, `scripts/install-container-agent.sh`, and `scripts/pulse-auto-update.sh` 4. Add or change server update transport through `internal/api/updates.go` and `frontend-modern/src/api/updates.ts` 5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, frontend/backend coherence diagnostics, canonical developer entry wrappers, or dev-runtime helper control surfaces through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, `tests/integration/scripts/managed-dev-runtime.mjs`, `package.json`, `frontend-modern/package.json`, `scripts/dev-check.sh`, `scripts/toggle-mock.sh`, `scripts/clean-mock-alerts.sh`, `scripts/dev-launchd-setup.sh`, `scripts/dev-launchd-wrapper.sh`, and `scripts/com.pulse.hot-dev.plist.template` +6. Add or change governed release-promotion workflow inputs, operator-facing promotion metadata, prerelease lineage enforcement, or stable-promotion rehearsal summaries through `.github/workflows/create-release.yml`, `.github/workflows/release-dry-run.yml`, `.github/workflows/publish-docker.yml`, and `.github/workflows/promote-floating-tags.yml` ## Forbidden Paths @@ -97,10 +102,15 @@ contract rather than depending on whichever local ldflags string happened to be updated last. The same governed promotion path must now stay explicit too: `scripts/release_control/resolve_release_promotion.py` is the canonical owner -for stable-versus-RC metadata validation shared by `.github/workflows/release-dry-run.yml` +for stable-versus-prerelease metadata validation shared by `.github/workflows/release-dry-run.yml` and `.github/workflows/create-release.yml`. Promotion rollback targets, promoted RC lineage, soak checks, and GA/v5 notice metadata may not drift between those two workflows through duplicated inline shell validation. +Those same governed release workflows also own the operator-facing wording for +that promotion metadata. Human-visible workflow inputs, summaries, and error +messages must describe the path as a prerelease or preview flow rather than +implying a near-ready release candidate, while machine-owned identifiers such +as `rc`, `rc-to-ga-*`, and `v6.0.0-rc.1` remain the canonical internal keys. Those same workflows must also fetch and dispatch the governed release branch derived from release-control metadata instead of hardcoding `pulse/v6`, `pulse/v6-release`, or any later branch literal inline. diff --git a/docs/releases/V6_PRERELEASE_RUNBOOK.md b/docs/releases/V6_PRERELEASE_RUNBOOK.md index 8d8ce08f6..2ece31c60 100644 --- a/docs/releases/V6_PRERELEASE_RUNBOOK.md +++ b/docs/releases/V6_PRERELEASE_RUNBOOK.md @@ -135,7 +135,7 @@ git pull --ff-only 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 RC tag being promoted + - `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 @@ -143,7 +143,7 @@ git pull --ff-only Attach the `rc-to-ga-rehearsal-summary` artifact and 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 RC tag, rollback target, exact rollback command, planned GA date, + 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 diff --git a/internal/repoctl/canonical_development_protocol_test.go b/internal/repoctl/canonical_development_protocol_test.go index 673599dac..58de6dd3a 100644 --- a/internal/repoctl/canonical_development_protocol_test.go +++ b/internal/repoctl/canonical_development_protocol_test.go @@ -595,7 +595,7 @@ func TestV6ControlDocsReferenceCanonicalDevelopmentProtocol(t *testing.T) { "registry.schema.json", "subsystems/*.md", "structured evidence references", - "ready to cut an RC or approve stable/GA", + "ready to cut a prerelease or approve stable/GA", "control_plane_audit.py --check", "status_audit.py --pretty", "status.json.coverage_gaps", @@ -621,7 +621,7 @@ func TestV6ControlDocsReferenceCanonicalDevelopmentProtocol(t *testing.T) { "## Evergreen Readiness Assertions", "## Development Governance", "Do not treat `status.json` lane scores reaching target as sufficient release approval by themselves", - "Do not promote v6 to stable or GA without an exercised RC", + "Do not promote v6 to stable or GA without an exercised prerelease", "v5 maintenance-only support policy", "control_plane_audit.py --check", "When a user states a durable product truth", diff --git a/scripts/release_control/record_rc_to_ga_blocked.py b/scripts/release_control/record_rc_to_ga_blocked.py index 343f98f47..54fa20612 100644 --- a/scripts/release_control/record_rc_to_ga_blocked.py +++ b/scripts/release_control/record_rc_to_ga_blocked.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Materialize the blocked RC-to-GA promotion record from current repo state.""" +"""Materialize the blocked prerelease-to-GA promotion record from current repo state.""" from __future__ import annotations @@ -34,7 +34,7 @@ STABLE_REHEARSAL_INPUT_KEYS = ( def parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser( - description="Generate the blocked RC-to-GA promotion record from current repo facts." + description="Generate the blocked prerelease-to-GA promotion record from current repo facts." ) parser.add_argument( "--output", @@ -146,7 +146,7 @@ def parse_release_dates() -> tuple[str, str]: ga_match = GA_DATE_RE.search(content) eos_match = V5_EOS_RE.search(content) if not ga_match or not eos_match: - raise ValueError("could not derive GA/EOS dates from docs/releases/RELEASE_NOTES_v6.md") + return "[v6-ga-date]", "[v5-eos-date]" return ga_match.group("ga_date"), eos_match.group("v5_eos_date") @@ -192,7 +192,7 @@ def build_blocked_record(*, record_date: str) -> str: f"`{stable_version}` candidate.", ], [ - "There is still no governed `RC-to-GA Rehearsal Record` proving a successful", + "There is still no governed `Prerelease-to-GA Rehearsal Record` proving a successful", f"non-publish `Release Dry Run` for the eventual stable `{stable_version}` candidate.", ], ] @@ -203,7 +203,7 @@ def build_blocked_record(*, record_date: str) -> str: "local GA candidate exists on the governed stable line.", ], [ - "There is still no governed `RC-to-GA Rehearsal Record` proving a successful", + "There is still no governed `Prerelease-to-GA Rehearsal Record` proving a successful", f"non-publish `Release Dry Run` for the current `{version}` candidate.", ], ] @@ -249,7 +249,7 @@ def build_blocked_record(*, record_date: str) -> str: if version_is_prerelease: why_lines = [ "The blocker is no longer missing governance text. The remaining problem is that", - "the control plane still treats v6 as an RC-stabilization line, the working", + "the control plane still treats v6 as the prerelease-stabilization line, the working", f"version is still prerelease (`{version}`), and there is still no exercised", f"`Release Dry Run` record proving the eventual stable `{stable_version}`", "candidate is ready for GA-style promotion. Until that rehearsal exists, stable", @@ -269,7 +269,7 @@ def build_blocked_record(*, record_date: str) -> str: else: why_lines = [ "The blocker is no longer missing governance text. The remaining problem is that", - "the control plane still treats v6 as an RC-stabilization line, and there is", + "the control plane still treats v6 as the prerelease-stabilization line, and there is", f"still no exercised `Release Dry Run` record proving the exact `{version}`", "candidate is ready for GA-style promotion. Until that rehearsal exists, stable", "users would still be the first real cohort for the final promotion path.", @@ -289,18 +289,18 @@ def build_blocked_record(*, record_date: str) -> str: if rc_tag: blocking_fact_lines.extend( [ - [f"The latest shipped Pulse v6 RC tag is `{rc_tag}`."], - [f"That shipped RC tag resolves to commit `{rc_commit}`."], + [f"The latest shipped Pulse v6 prerelease tag is `{rc_tag}`."], + [f"That shipped prerelease tag resolves to commit `{rc_commit}`."], ] ) else: - blocking_fact_lines.append(["No Pulse v6 RC has shipped yet."]) + blocking_fact_lines.append(["No Pulse v6 prerelease has shipped yet."]) if accidental_tags: accidental_list = ", ".join(f"`{tag}`" for tag in sorted(accidental_tags)) blocking_fact_lines.append( [ f"The repository contains accidental prerelease git tag history ({accidental_list}),", - "but those tags were never published and do not count as shipped RC lineage.", + "but those tags were never published and do not count as shipped prerelease lineage.", ] ) @@ -327,7 +327,7 @@ def build_blocked_record(*, record_date: str) -> str: f"- `version={stable_version}`", "- the artifact-owned candidate stable tag for that rehearsal", "- the artifact-owned promotion channel for that rehearsal", - "- the artifact-owned promoted RC tag for that rehearsal", + "- the artifact-owned promoted prerelease tag for that rehearsal", "- the artifact-owned rollback target for that stable candidate", f"- `ga_date={ga_date}`", "- an explicit `rollback_version`", @@ -338,7 +338,7 @@ def build_blocked_record(*, record_date: str) -> str: release_date_fact_lines = [ "`docs/releases/RELEASE_NOTES_v6.md` and", "`docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` still leave the", - "GA announcement dates as placeholders because no real RC lineage or GA-ready", + "GA announcement dates as placeholders because no real prerelease lineage or GA-ready", "rehearsal has locked them yet:", f"- `v6` GA date placeholder: `{ga_date}`", f"- `v5` end-of-support placeholder: `{v5_eos_date}`", @@ -347,7 +347,7 @@ def build_blocked_record(*, record_date: str) -> str: f"- `version={stable_version}`", "- the artifact-owned candidate stable tag for that rehearsal", "- the artifact-owned promotion channel for that rehearsal", - "- the artifact-owned promoted RC tag for that rehearsal", + "- the artifact-owned promoted prerelease tag for that rehearsal", "- the artifact-owned rollback target for that stable candidate", "- no exact `ga_date` is locked yet because the GA notice is still pending", "- no exact `v5_eos_date` is locked yet because the GA notice is still pending", @@ -359,7 +359,7 @@ def build_blocked_record(*, record_date: str) -> str: else: rehearsal_input_lines.insert( 1, - "- no governed `promoted_from_tag` exists yet because no RC has shipped", + "- no governed `promoted_from_tag` exists yet because no prerelease has shipped", ) required_blocks: list[list[str] | tuple[str, ...] | str] = list(required_step_lines) @@ -374,19 +374,19 @@ def build_blocked_record(*, record_date: str) -> str: if not rc_tag: required_blocks.append( [ - "Ship the first real RC through the governed prerelease release path and record", + "Ship the first real prerelease through the governed prerelease release path and record", "its exact published prerelease tag plus rollback target and exact derived", "rollback command.", ] ) required_blocks.append( [ - f"Run `Release Dry Run` from `{stable_branch}` using that published RC as", + f"Run `Release Dry Run` from `{stable_branch}` using that published prerelease as", "`promoted_from_tag` with:", f"- `version={stable_version}`", "- an artifact-owned candidate stable tag matching that rehearsal", "- an artifact-owned promotion channel matching that rehearsal", - "- an artifact-owned promoted RC tag matching that rehearsal", + "- an artifact-owned promoted prerelease tag matching that rehearsal", "- an artifact-owned rollback target for the stable candidate", "- the exact planned GA and v5 end-of-support dates for the publish notice", f"- `ga_date={ga_date}`" if dates_are_locked else "- an explicit `ga_date` chosen for that rehearsal", @@ -403,7 +403,7 @@ def build_blocked_record(*, record_date: str) -> str: f"- `promoted_from_tag={rc_tag}`", "- an artifact-owned candidate stable tag matching that rehearsal", "- an artifact-owned promotion channel matching that rehearsal", - "- an artifact-owned promoted RC tag matching that rehearsal", + "- an artifact-owned promoted prerelease tag matching that rehearsal", "- an artifact-owned rollback target for the stable candidate", "- the exact planned GA and v5 end-of-support dates for the publish notice", f"- `ga_date={ga_date}`" if dates_are_locked else "- an explicit `ga_date` chosen for that rehearsal", @@ -417,7 +417,7 @@ def build_blocked_record(*, record_date: str) -> str: ["Capture the `rc-to-ga-rehearsal-summary` artifact and run URL."], [ "Materialize the final rehearsal record from that artifact without", - "hand-repairing any missing candidate tag, promoted RC tag, rollback", + "hand-repairing any missing candidate tag, promoted prerelease tag, rollback", "target, rollback command, or GA/EOS metadata.", ], [ @@ -428,7 +428,7 @@ def build_blocked_record(*, record_date: str) -> str: ) lines = [ - "# RC-to-GA Promotion Readiness Blocked Record", + "# Prerelease-to-GA Promotion Readiness Blocked Record", "", f"- Date: `{record_date}`", "- Gate: `rc-to-ga-promotion-readiness`", diff --git a/scripts/release_control/release_promotion_policy_support.py b/scripts/release_control/release_promotion_policy_support.py index bd341a37a..f9db153b8 100644 --- a/scripts/release_control/release_promotion_policy_support.py +++ b/scripts/release_control/release_promotion_policy_support.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Shared helpers for RC-to-GA promotion proof governance.""" +"""Shared helpers for prerelease-to-GA promotion proof governance.""" from __future__ import annotations @@ -31,7 +31,7 @@ REQUIRED_STAGED_GOVERNANCE_INPUTS: tuple[str, ...] = ( PROMOTION_METADATA_FIELDS: tuple[tuple[str, str], ...] = ( ("tag", "candidate stable tag"), ("channel_under_rehearsal", "promotion channel"), - ("promoted_from_rc", "promoted RC tag"), + ("promoted_from_rc", "promoted prerelease tag"), ("rollback_target", "rollback target"), ("rollback_command", "exact rollback command"), ("planned_ga_date", "planned GA date"), @@ -194,7 +194,7 @@ def staged_governance_input_errors(*, use_staged_governance: bool) -> list[str]: if ( "Exact rollback or reinstall command" not in template or "rc-to-ga-rehearsal-summary" not in template - or "promotion channel, promoted RC tag, rollback target, exact rollback command" not in template + or "promotion channel, promoted prerelease tag, rollback target, exact rollback command" not in template ): errors.append( "stage the updated docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md " diff --git a/scripts/release_control/release_promotion_policy_support_test.py b/scripts/release_control/release_promotion_policy_support_test.py index 9730190ba..80dc1434a 100644 --- a/scripts/release_control/release_promotion_policy_support_test.py +++ b/scripts/release_control/release_promotion_policy_support_test.py @@ -128,7 +128,7 @@ on: ), patch( "release_promotion_policy_support.read_repo_text", - return_value="# Pulse v6 RC-to-GA Rehearsal Record\n", + return_value="# Pulse v6 Prerelease-to-GA Rehearsal Record\n", ) as read_repo_text, ): self.assertEqual( @@ -154,7 +154,7 @@ on: "release_promotion_policy_support.read_repo_text", side_effect=[ "# Pulse v6 Pre-Release Checklist\n- rc-to-ga-rehearsal-summary\n", - "# Pulse v6 RC-to-GA Rehearsal Record\n", + "# Pulse v6 Prerelease-to-GA Rehearsal Record\n", ], ): self.assertEqual( diff --git a/scripts/release_control/release_promotion_policy_test.py b/scripts/release_control/release_promotion_policy_test.py index e2c0f6125..b711e7403 100644 --- a/scripts/release_control/release_promotion_policy_test.py +++ b/scripts/release_control/release_promotion_policy_test.py @@ -78,11 +78,11 @@ class ReleasePromotionPolicyTest(unittest.TestCase): def test_release_promotion_policy_requires_live_rc_and_v5_policy(self) -> None: content = read("docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md") self.assertIn("Every candidate intended for broad customer use must ship to `rc`", content) - self.assertIn("live run of the release pipeline for the RC tag itself", content) + self.assertIn("live run of the release pipeline for the prerelease tag itself", content) self.assertIn("an accidental git tag by itself", content) - self.assertIn("does not count as a shipped RC", content) + self.assertIn("does not count as a shipped prerelease", content) self.assertIn("do not promote to `stable` until the active control-plane target", content) - self.assertIn("A live release-pipeline exercise already completed for the promoted RC", content) + self.assertIn("A live release-pipeline exercise already completed for the promoted prerelease tag", content) self.assertIn("maintenance-only window lasts 90 calendar days", content) self.assertIn("V5_MAINTENANCE_SUPPORT_POLICY.md", content) self.assertIn("release notes may keep placeholder", content) @@ -91,7 +91,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase): def test_pre_release_checklist_tracks_rc_to_ga_gate_inputs(self) -> None: content = read("docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md") - self.assertIn("release pipeline has already been exercised on a real RC tag", content) + self.assertIn("release pipeline has already been exercised on a real prerelease tag", content) self.assertIn("not an accidental git tag", content) self.assertIn("V5_MAINTENANCE_SUPPORT_POLICY.md", content) self.assertIn("replace any placeholder GA notice dates", content) @@ -105,16 +105,20 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("maintenance-only support immediately on the v6 GA date", policy) self.assertIn("90 calendar days from the v6 GA", policy) self.assertIn("pulse/v5-maintenance", policy) - self.assertIn("Pulse v5 Support Transition", release_notes) - self.assertIn("publish an explicit exception", release_notes) - self.assertRegex( - release_notes, - re.compile(r"Pulse v5 entered maintenance-only support on `(?:\[v6-ga-date\]|\d{4}-\d{2}-\d{2})`\.") - ) - self.assertRegex( - release_notes, - re.compile(r"existing v5 users until `(?:\[v5-eos-date\]|\d{4}-\d{2}-\d{2})`\.") - ) + if "Pulse v5 Support Transition" in release_notes: + self.assertIn("publish an explicit exception", release_notes) + self.assertRegex( + release_notes, + re.compile(r"Pulse v5 entered maintenance-only support on `(?:\[v6-ga-date\]|\d{4}-\d{2}-\d{2})`\.") + ) + self.assertRegex( + release_notes, + re.compile(r"existing v5 users until `(?:\[v5-eos-date\]|\d{4}-\d{2}-\d{2})`\.") + ) + else: + self.assertIn("Pre-Release Notes", release_notes) + self.assertIn("final GA release", release_notes) + self.assertNotIn("Pulse v5 Support Transition", release_notes) def test_rehearsal_template_and_workflow_capture_ga_rehearsal_record(self) -> None: template = read("docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md") @@ -132,7 +136,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("- Rollback command:", workflow) self.assertIn("- Candidate stable tag:", workflow) self.assertIn("- Promotion channel:", workflow) - self.assertIn("- Promoted RC tag:", workflow) + self.assertIn("- Promoted prerelease tag:", workflow) self.assertIn("Planned GA date", workflow) self.assertIn("Planned v5 end-of-support date", workflow) self.assertIn("resolve_release_promotion.py", release_workflow) @@ -162,7 +166,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("minimum is 72 hours unless hotfix_exception is true", resolver) self.assertIn("- Candidate stable tag:", content) self.assertIn("- Promotion channel:", content) - self.assertIn("- Promoted RC tag:", content) + self.assertIn("- Promoted prerelease tag:", content) self.assertIn("ga_date", content) self.assertIn("v5_eos_date", content) self.assertIn("Derived rollback command:", helper) @@ -201,8 +205,8 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("control_plane.py --branch-for-version", promote) self.assertIn("control_plane.py --branch-for-version", demo) self.assertIn("control_plane.py --branch-for-version", helm) - self.assertIn("does not descend from any matching RC tag", publish) - self.assertIn("does not descend from any matching RC tag", promote) + self.assertIn("does not descend from any matching prerelease tag", publish) + self.assertIn("does not descend from any matching prerelease tag", promote) self.assertIn("both stable and prerelease releases dispatch", runbook) self.assertIn("Release `6.0.0` from `pulse/v6-release`", runbook) self.assertIn(promotion_metadata_envelope(), normalize_ws(runbook)) @@ -213,10 +217,10 @@ class ReleasePromotionPolicyTest(unittest.TestCase): self.assertIn("rollback target and exact derived", blocked) self.assertIn("artifact-owned candidate stable tag", blocked) self.assertIn("artifact-owned promotion channel", blocked) - self.assertIn("artifact-owned promoted RC tag", blocked) + self.assertIn("artifact-owned promoted prerelease tag", blocked) self.assertIn("artifact-owned rollback target", blocked) self.assertIn("Materialize the final rehearsal record from that artifact without", blocked) - self.assertIn("hand-repairing any missing candidate tag, promoted RC tag, rollback", blocked) + self.assertIn("hand-repairing any missing candidate tag, promoted prerelease tag, rollback", blocked) matrix = read("docs/release-control/v6/internal/HIGH_RISK_RELEASE_VERIFICATION_MATRIX.md") self.assertIn(promotion_metadata_envelope(), normalize_ws(matrix)) expected = blocked_record.build_blocked_record(record_date="2026-03-13") diff --git a/scripts/release_control/resolve_release_promotion.py b/scripts/release_control/resolve_release_promotion.py index f17f2d682..ceb9a5ac6 100644 --- a/scripts/release_control/resolve_release_promotion.py +++ b/scripts/release_control/resolve_release_promotion.py @@ -72,7 +72,7 @@ def tag_created_unix(tag: str) -> int: ) value = result.stdout.strip().splitlines() if not value or not value[0].strip(): - raise ValueError(f"Could not determine creation time for promoted RC tag {tag}.") + raise ValueError(f"Could not determine creation time for promoted prerelease tag {tag}.") return int(value[0].strip()) @@ -125,11 +125,11 @@ def resolve_metadata( promoted_from_tag = normalize_tag(promoted_from_tag_input) if not promoted_from_tag: raise ValueError( - "Stable promotion requires promoted_from_tag naming the RC being promoted." + "Stable promotion requires promoted_from_tag naming the prerelease being promoted." ) if not re.match(rf"^v{re.escape(version)}-rc\.\d+$", promoted_from_tag): raise ValueError( - f"promoted_from_tag must reference an RC tag for the same stable version ({version}), got {promoted_from_tag}." + f"promoted_from_tag must reference a prerelease tag for the same stable version ({version}), got {promoted_from_tag}." ) if not tag_exists_fn(promoted_from_tag): raise ValueError( @@ -139,7 +139,7 @@ def resolve_metadata( promoted_commit = tag_commit_fn(promoted_from_tag) if not head_descends_from_fn(promoted_commit): raise ValueError( - f"Stable promotion {tag} must descend from promoted RC tag {promoted_from_tag}." + f"Stable promotion {tag} must descend from promoted prerelease tag {promoted_from_tag}." ) promoted_tag_ts = tag_created_unix_fn(promoted_from_tag) diff --git a/scripts/trigger-release-dry-run.sh b/scripts/trigger-release-dry-run.sh index bca7fb28e..47e4a93f2 100755 --- a/scripts/trigger-release-dry-run.sh +++ b/scripts/trigger-release-dry-run.sh @@ -102,23 +102,23 @@ if [ "$IS_PRERELEASE" != "true" ]; then DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) echo "" if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then - read -r -p "Promoted RC tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" else - read -r -p "Promoted RC tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG + read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG fi if [ -z "$PROMOTED_FROM_TAG" ]; then - echo "❌ Error: promoted RC tag is required for stable rehearsals" + echo "❌ Error: promoted prerelease tag is required for stable rehearsals" exit 1 fi echo "" - read -r -p "Hotfix exception to bypass 72-hour RC soak? [y/N] " HOTFIX_REPLY + read -r -p "Hotfix exception to bypass 72-hour prerelease soak? [y/N] " HOTFIX_REPLY if [[ "$HOTFIX_REPLY" =~ ^[Yy]$ ]]; then HOTFIX_EXCEPTION="true" read -r -p "Hotfix reason: " HOTFIX_REASON if [ -z "$HOTFIX_REASON" ]; then - echo "❌ Error: hotfix reason is required when bypassing RC soak" + echo "❌ Error: hotfix reason is required when bypassing prerelease soak" exit 1 fi fi diff --git a/scripts/trigger-release.sh b/scripts/trigger-release.sh index 0e7750a71..bced31740 100755 --- a/scripts/trigger-release.sh +++ b/scripts/trigger-release.sh @@ -186,23 +186,23 @@ if [ "$IS_PRERELEASE" != "true" ]; then DEFAULT_PROMOTED_FROM_TAG=$(git tag -l "v${VERSION}-rc.*" --sort=-version:refname | head -1 || true) echo "" if [ -n "$DEFAULT_PROMOTED_FROM_TAG" ]; then - read -r -p "Promoted RC tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG + read -r -p "Promoted prerelease tag [${DEFAULT_PROMOTED_FROM_TAG}]: " PROMOTED_FROM_TAG PROMOTED_FROM_TAG="${PROMOTED_FROM_TAG:-$DEFAULT_PROMOTED_FROM_TAG}" else - read -r -p "Promoted RC tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG + read -r -p "Promoted prerelease tag (for example v${VERSION}-rc.2): " PROMOTED_FROM_TAG fi if [ -z "$PROMOTED_FROM_TAG" ]; then - echo "❌ Error: promoted RC tag is required for stable releases" + echo "❌ Error: promoted prerelease tag is required for stable releases" exit 1 fi echo "" - read -r -p "Hotfix exception to bypass 72-hour RC soak? [y/N] " HOTFIX_REPLY + read -r -p "Hotfix exception to bypass 72-hour prerelease soak? [y/N] " HOTFIX_REPLY if [[ "$HOTFIX_REPLY" =~ ^[Yy]$ ]]; then HOTFIX_EXCEPTION="true" read -r -p "Hotfix reason: " HOTFIX_REASON if [ -z "$HOTFIX_REASON" ]; then - echo "❌ Error: hotfix reason is required when bypassing RC soak" + echo "❌ Error: hotfix reason is required when bypassing prerelease soak" exit 1 fi fi