diff --git a/VERSION b/VERSION index 68411c7d7..cbb8dc1f3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.4.0-rc.7 +6.4.0-rc.8 diff --git a/deploy/helm/pulse/Chart.yaml b/deploy/helm/pulse/Chart.yaml index 66914f0b9..0a83214f0 100644 --- a/deploy/helm/pulse/Chart.yaml +++ b/deploy/helm/pulse/Chart.yaml @@ -2,9 +2,9 @@ apiVersion: v2 name: pulse description: Helm chart for deploying the Pulse hub and optional Docker, Kubernetes, or OpenShift monitoring agent. type: application -version: 6.4.0-rc.7 -appVersion: "6.4.0-rc.7" -icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.4.0-rc.7/docs/images/pulse-logo.svg +version: 6.4.0-rc.8 +appVersion: "6.4.0-rc.8" +icon: https://raw.githubusercontent.com/rcourtman/Pulse/v6.4.0-rc.8/docs/images/pulse-logo.svg keywords: - monitoring - proxmox @@ -32,7 +32,7 @@ annotations: description: Smoke tests with kind cluster deployment artifacthub.io/links: | - name: Documentation - url: https://github.com/rcourtman/Pulse/blob/v6.4.0-rc.7/docs/KUBERNETES.md + url: https://github.com/rcourtman/Pulse/blob/v6.4.0-rc.8/docs/KUBERNETES.md - name: Support url: https://github.com/rcourtman/Pulse/discussions artifacthub.io/maintainers: | diff --git a/deploy/helm/pulse/README.md b/deploy/helm/pulse/README.md index 40720142b..a142719c2 100644 --- a/deploy/helm/pulse/README.md +++ b/deploy/helm/pulse/README.md @@ -1,6 +1,6 @@ # pulse -![Version: 6.4.0-rc.7](https://img.shields.io/badge/Version-6.4.0--rc.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.4.0-rc.7](https://img.shields.io/badge/AppVersion-6.4.0--rc.7-informational?style=flat-square) +![Version: 6.4.0-rc.8](https://img.shields.io/badge/Version-6.4.0--rc.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 6.4.0-rc.8](https://img.shields.io/badge/AppVersion-6.4.0--rc.8-informational?style=flat-square) Helm chart for deploying the Pulse hub and optional Docker, Kubernetes, or OpenShift monitoring agent. diff --git a/docker-compose.yml b/docker-compose.yml index 6836208c4..c5024260b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: pulse: - image: ${PULSE_IMAGE:-rcourtman/pulse:6.4.0-rc.7} + image: ${PULSE_IMAGE:-rcourtman/pulse:6.4.0-rc.8} container_name: pulse restart: unless-stopped logging: diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index 85a18fb35..14cb67e09 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -7,8 +7,8 @@ For historical v4 notes that previously lived in this repo, see: `docs/releases/RELEASE_NOTES_v4.md` For the current v6 release candidate packet (the current v6 support release candidate packet), see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md` For the current stable v6 packet, see: - `docs/releases/RELEASE_NOTES_v6.3.2.md` @@ -19,10 +19,12 @@ For the preceding stable v6 packet, see: - `docs/releases/V6_CHANGELOG_v6.3.1.md` For the preceding v6.4 release candidate packet, see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` For earlier v6.4 release candidate packets, see: +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` - `docs/releases/RELEASE_NOTES_v6.4.0-rc.5.md` - `docs/releases/V6_CHANGELOG_v6.4.0-rc.5.md` - `docs/releases/RELEASE_NOTES_v6.4.0-rc.4.md` diff --git a/docs/UPGRADE_v6.md b/docs/UPGRADE_v6.md index 440f05c41..bcae3da75 100644 --- a/docs/UPGRADE_v6.md +++ b/docs/UPGRADE_v6.md @@ -4,8 +4,8 @@ This guide covers practical upgrade steps for existing Pulse installs moving to For the current v6 release candidate packet (the current v6 support release candidate packet), see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md` For the current stable v6 packet, see: @@ -19,11 +19,14 @@ For the preceding stable v6 packet, see: For the preceding v6.4 release candidate packet, see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` For earlier v6.4 release candidate packets, see: +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` + - `docs/releases/RELEASE_NOTES_v6.4.0-rc.5.md` - `docs/releases/V6_CHANGELOG_v6.4.0-rc.5.md` - `docs/releases/RELEASE_NOTES_v6.4.0-rc.4.md` diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 6cccf6ac6..a9adabae3 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -1811,16 +1811,20 @@ diagnostics. The same release workflow also executes the generated self-signed and custom-CA Windows installer commands through Windows PowerShell 5.1 before release assembly, so the first HTTPS fetch is release proof rather than a string-shape assertion. -The active prerelease `v6.4.0-rc.7` cut sets the repo-root `VERSION`, repo-root +The active prerelease `v6.4.0-rc.8` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and -Helm chart release metadata to the same `6.4.0-rc.7` release version. It follows -`v6.4.0-rc.6` on the published `v6.4.0` candidate line. This prerelease keeps +Helm chart release metadata to the same `6.4.0-rc.8` release version. It follows +`v6.4.0-rc.7` on the published `v6.4.0` candidate line. That candidate was +quarantined before activation, so `v6.4.0-rc.8` follows `v6.4.0-rc.6` as the +next publicly activated candidate. This prerelease keeps `rollback_version=v6.3.2`, publishes a versioned public GitHub prerelease plus versioned Docker and Helm artifacts, and does not move stable/latest install pointers or stable semver aliases. The candidate makes the append-only event log authoritative for alert history and active-state reconstruction; adds per-alert snooze, recurring scoped maintenance, destination severity routing, repeatable escalation schedules, and external dead-man monitoring; +keeps informational alert severity distinct across configuration, persistence, +API responses, filters, email, ntfy, and mobile push presentation; adds rolling-window metric policy and predictive storage-capacity alerts; makes host SMART policy configurable without duplicating Proxmox disk risk; converges infrastructure detail presentation; and strengthens independently @@ -1845,9 +1849,16 @@ only after the release owner explicitly confirms that production credentials and certificate authorization are ready and a reviewed policy/code change restores it. +The preceding `v6.4.0-rc.7` publication attempt built and staged exact candidate +artifacts from source SHA `595c369d85796f86855b4cf8335b9bb371d28462`, +but the backend release gate failed before public activation. Its tag and +versioned artifacts remain immutable, and `v6.4.0-rc.8` supersedes the failed +candidate without moving stable install pointers or stable semver aliases from +`v6.3.2`. + The preceding `v6.4.0-rc.6` cut published from exact source SHA `8fde82b8a24229fffb628732d10fc320be643099`. Its tag and versioned artifacts -remain immutable; `v6.4.0-rc.7` supersedes it without moving stable install +remain immutable; later `v6.4.0` prereleases supersede it without moving stable install pointers or stable semver aliases from `v6.3.2`. The preceding `v6.4.0-rc.5` cut published from exact source SHA @@ -2302,8 +2313,8 @@ For the active stable `v6.1.2` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `6.1.2` whenever the governed `VERSION` is that stable cut. The stable promotion guard remains in force and rejects leftover `-rc.` defaults. -For the active prerelease `v6.4.0-rc.7` cut, the repo-root compose default and -`scripts/install-docker.sh` fallback must both pin `6.4.0-rc.7` until the next +For the active prerelease `v6.4.0-rc.8` cut, the repo-root compose default and +`scripts/install-docker.sh` fallback must both pin `6.4.0-rc.8` until the next governed stable cut moves them forward. Each new release moves these two pins together with the repo-root `VERSION` and the Helm chart metadata in the same commit; a cut that leaves any of the four on a superseded value is a diff --git a/docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md b/docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md new file mode 100644 index 000000000..4f42b4d69 --- /dev/null +++ b/docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md @@ -0,0 +1,24 @@ +# Pulse v6.4.0-rc.8 Release Notes + +`v6.4.0-rc.8` strengthens alerting as an operational system. Histories survive restarts, alerts can be scheduled and routed more precisely, and new forecasting detects storage risk earlier. + +## What's improved + +- **Durable alert lifecycles** - Alert history and active state now rebuild from the event log after restarts, with persisted identities migrated automatically and false all-clear states prevented during hydration. +- **Better notification control** - Alerts can be snoozed individually, maintenance can recur by scope, escalation repeats can target specific destinations, delivery routes can filter by severity, and informational events remain distinct from warnings. +- **Earlier capacity warnings** - Rolling metric windows and predictive storage forecasts surface sustained pressure and likely exhaustion before a single threshold breach becomes an outage. +- **Host disk policies** - SMART sector, media, endurance, spare, and CRC thresholds can be tuned per host while Proxmox-linked agents continue to avoid duplicate disk-risk alerts. +- **External availability monitoring** - Dead-man checks can notify when an expected external signal stops arriving, with configuration and recovery state persisted. +- **Clearer infrastructure details** - Resource drawers, Proxmox backup views, and alert timelines present more complete and consistent context across desktop and narrow layouts. +- **Safer governed actions** - Docker action results now carry independently observed post-action state, while deployment enrollment and credential changes persist atomically. + +## Before you upgrade + +- This is a release candidate. Stable installations remain on v6.3.2 unless an operator explicitly selects this version. +- Existing configurations remain valid. Alert identity and history migrations run automatically, with no manual data migration required. +- Existing Pulse Mobile iOS build 12 and Android versionCode 9 remain compatible. The new `alert_fired` push uses the already-supported `view_alert` action and existing informational severity presentation, so no companion update is required for this candidate. +- Windows Unified Agent binaries are checksum- and detached-signature-verified but are not Authenticode-signed, so Windows may show an Unknown Publisher warning. + +## Known issues + +- Windows Authenticode signing remains unavailable for this candidate. Use the published checksum and detached signature when verifying Windows agent downloads. diff --git a/docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md b/docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md new file mode 100644 index 000000000..ea3ab4061 --- /dev/null +++ b/docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md @@ -0,0 +1,45 @@ +# Pulse v6.4.0-rc.8 + +_This changelog describes the changes since `v6.4.0-rc.7` included in +`v6.4.0-rc.8`. The `v6.4.0-rc.7` candidate was quarantined before public +activation, so the customer-visible entries below remain cumulative from +`v6.4.0-rc.6`._ + +## Added + +- Rolling-window metric evaluation supports sustained CPU and memory policies, including workload inheritance from host defaults. +- Predictive storage-capacity alerts estimate exhaustion risk from retained usage history and recover when the forecast clears. +- Per-alert snooze, recurring scoped maintenance, destination severity routing, repeatable escalation schedules, and external dead-man monitoring expand operator control over alert delivery. +- Resolved host SMART policy covers health failure, sector counters, media errors, remaining life, NVMe spare, and CRC growth without creating duplicate Proxmox disk alerts. +- Canonical `alert_fired` push events use the existing mobile `view_alert` navigation action. +- Informational alerts now retain an explicit `info` severity through configuration, persistence, API responses, filtering, notification routing, and display. + +## Changed + +- The append-only event log is the authority for alert history and active lifecycle reconstruction, including restart recovery, acknowledgement, resolution, suppression, notification, and migration evidence. +- Alert identities and persisted history migrate to canonical resource keys, while active state uses durable atomic snapshots and ordered recovery. +- Escalation and delivery decisions are destination-specific, repeated holds are coalesced, and destination updates persist before the active runtime changes. +- Resource detail drawers use shared information-card and detail-table primitives across infrastructure, Docker, storage, and Proxmox backup surfaces. +- Docker lifecycle results distinguish command acceptance from independently observed post-action state, and deployment enrollment plus credential updates commit atomically. +- Email, ntfy, and mobile push presentation preserve informational priority instead of elevating non-warning events to warning treatment. + +## Fixed + +- Alert hydration no longer exposes a false all-clear state before persisted incidents are restored. +- Restart recovery, history queries, and mock alert timelines preserve lifecycle order, observation time, and complete incident evidence. +- Fresh rolling-window metric data remains authoritative, including when older samples or counter resets are present. +- Offline mock hosts remain on the normal host-alert lifecycle instead of losing active incidents during refresh. +- API token watcher updates remain ordered across successive persistence mutations. +- Proxmox backup health, inventory refresh, offline fixtures, and drawer detail presentation retain complete current context. + +## Release Metadata + +- Version: `v6.4.0-rc.8` +- Previous candidate tag: `v6.4.0-rc.7` +- Previous published candidate: `v6.4.0-rc.6` +- Previous stable: `v6.3.2` +- Rollback target: `v6.3.2` +- Rollback command: `./scripts/install.sh --version v6.3.2` +- Promotion path: exact-SHA single-build release candidate from `main` +- Windows signing decision: prereleases publish checksum- and detached-signature-verified Windows agents without Authenticode while SignPath remains unavailable. Windows may show an Unknown Publisher warning. +- Mobile decision: `existing-mobile-build-compatible`. Published iOS build 12 and Android versionCode 9 already route `action_type=view_alert`, accept severity as a string, and render informational severity, so no companion upload is required. diff --git a/frontend-modern/public/docs/UPGRADE_v6.md b/frontend-modern/public/docs/UPGRADE_v6.md index 440f05c41..bcae3da75 100644 --- a/frontend-modern/public/docs/UPGRADE_v6.md +++ b/frontend-modern/public/docs/UPGRADE_v6.md @@ -4,8 +4,8 @@ This guide covers practical upgrade steps for existing Pulse installs moving to For the current v6 release candidate packet (the current v6 support release candidate packet), see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.8.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.8.md` For the current stable v6 packet, see: @@ -19,11 +19,14 @@ For the preceding stable v6 packet, see: For the preceding v6.4 release candidate packet, see: -- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` -- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.7.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.7.md` For earlier v6.4 release candidate packets, see: +- `docs/releases/RELEASE_NOTES_v6.4.0-rc.6.md` +- `docs/releases/V6_CHANGELOG_v6.4.0-rc.6.md` + - `docs/releases/RELEASE_NOTES_v6.4.0-rc.5.md` - `docs/releases/V6_CHANGELOG_v6.4.0-rc.5.md` - `docs/releases/RELEASE_NOTES_v6.4.0-rc.4.md` diff --git a/scripts/install-docker.sh b/scripts/install-docker.sh index eaec53fb1..e1bc00940 100755 --- a/scripts/install-docker.sh +++ b/scripts/install-docker.sh @@ -6,7 +6,7 @@ set -euo pipefail SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" DOCKER_IMAGE_REPO="${DOCKER_IMAGE_REPO:-rcourtman/pulse}" -CANONICAL_DEFAULT_PULSE_VERSION="6.4.0-rc.7" +CANONICAL_DEFAULT_PULSE_VERSION="6.4.0-rc.8" resolve_default_pulse_version() { if [ -n "${PULSE_IMAGE_VERSION:-}" ]; then diff --git a/scripts/installtests/build_release_assets_test.go b/scripts/installtests/build_release_assets_test.go index 082da444e..a58efa43e 100644 --- a/scripts/installtests/build_release_assets_test.go +++ b/scripts/installtests/build_release_assets_test.go @@ -889,6 +889,7 @@ func TestCurrentPrereleasePacketTracksInstallMetadata(t *testing.T) { "## Known issues", "Durable alert lifecycles", "Better notification control", + "informational events remain distinct from warnings", "Earlier capacity warnings", "Host disk policies", "External availability monitoring", @@ -909,9 +910,11 @@ func TestCurrentPrereleasePacketTracksInstallMetadata(t *testing.T) { "Rolling-window metric evaluation supports sustained CPU and memory policies", "Predictive storage-capacity alerts estimate exhaustion risk", "Per-alert snooze, recurring scoped maintenance, destination severity routing", + "Informational alerts now retain an explicit `info` severity through configuration, persistence, API responses, filtering, notification routing, and display.", "The append-only event log is the authority for alert history and active lifecycle reconstruction", "Alert hydration no longer exposes a false all-clear state", "Docker lifecycle results distinguish command acceptance from independently observed post-action state", + "Email, ntfy, and mobile push presentation preserve informational priority instead of elevating non-warning events to warning treatment.", "Windows signing decision: prereleases publish checksum- and detached-signature-verified Windows agents without Authenticode", "Mobile decision: `existing-mobile-build-compatible`", "Published iOS build 12 and Android versionCode 9 already route `action_type=view_alert`", @@ -960,7 +963,7 @@ func TestCurrentPrereleasePacketTracksInstallMetadata(t *testing.T) { "The active prerelease `v"+version+"` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and Helm chart release metadata to the same `"+version+"` release version.", "This prerelease keeps `rollback_version=v"+previous+"`, publishes a versioned public GitHub prerelease plus versioned Docker and Helm artifacts, and does not move stable/latest install pointers or stable semver aliases.", "For the active prerelease `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"` until the next governed stable cut moves them forward.", - "The changes since `v"+comparisonVersion+"` add the canonical `alert_fired` mobile push type, but preserve the existing `view_alert` navigation action and all route, request/response, pairing, and authorization contracts.", + "add the canonical `alert_fired` mobile push type, but preserve the existing `view_alert` navigation action and all route, request/response, pairing, and authorization contracts.", "Published Pulse Mobile iOS build 12 and Android versionCode 9 already route `action_type=view_alert`, so the server cut is classified `existing-mobile-build-compatible`; no companion upload or public mobile-store rollout is part of this candidate.", "The prerelease Windows path retains exact-SHA, checksum, and detached-signature verification without Authenticode. Stable `v"+stableTarget+"` also skips SignPath under the standing unavailable policy", ) @@ -3096,11 +3099,11 @@ func TestReleaseNotesGeneratorResolvesChannelSpecificComparisonRanges(t *testing commit("stable 6.3.2 hotfix") runGit("tag", "v6.3.2") runGit("checkout", "main") - for rc := 1; rc <= 6; rc++ { + for rc := 1; rc <= 7; rc++ { commit("release candidate " + strconv.Itoa(rc)) runGit("tag", "v6.4.0-rc."+strconv.Itoa(rc)) } - commit("release candidate 7 changes") + commit("release candidate 8 changes") generator, err := filepath.Abs(repoFile("scripts", "generate-release-notes.sh")) if err != nil { @@ -3138,8 +3141,8 @@ func TestReleaseNotesGeneratorResolvesChannelSpecificComparisonRanges(t *testing return strings.TrimSpace(string(output)) } - if got := resolve("6.4.0-rc.7"); got != "v6.4.0-rc.6" { - t.Fatalf("RC comparison base = %q, want v6.4.0-rc.6", got) + if got := resolve("6.4.0-rc.8"); got != "v6.4.0-rc.7" { + t.Fatalf("RC comparison base = %q, want v6.4.0-rc.7", got) } if got := resolve("6.4.0-rc.1"); got != "v6.3.2" { t.Fatalf("RC1 comparison base = %q, want v6.3.2", got) @@ -3148,13 +3151,13 @@ func TestReleaseNotesGeneratorResolvesChannelSpecificComparisonRanges(t *testing t.Fatalf("GA comparison base = %q, want v6.3.2", got) } - cmd := exec.Command("bash", generator, "6.4.0-rc.7", "v6.4.0-rc.5") + cmd := exec.Command("bash", generator, "6.4.0-rc.8", "v6.4.0-rc.6") cmd.Dir = repo output, err := cmd.CombinedOutput() if err == nil { t.Fatal("generator accepted a comparison tag older than the immediately preceding RC") } - if !strings.Contains(string(output), "expected 'v6.4.0-rc.6'") { + if !strings.Contains(string(output), "expected 'v6.4.0-rc.7'") { t.Fatalf("unexpected comparison-range rejection:\n%s", output) } } diff --git a/scripts/installtests/install_docker_sh_test.go b/scripts/installtests/install_docker_sh_test.go index 4e69a723d..c6297c6a2 100644 --- a/scripts/installtests/install_docker_sh_test.go +++ b/scripts/installtests/install_docker_sh_test.go @@ -148,6 +148,7 @@ func TestPreviousStableForPrereleaseVersionCrossesMinorBoundaries(t *testing.T) {version: "6.4.0-rc.5", want: "6.3.2"}, {version: "6.4.0-rc.6", want: "6.3.2"}, {version: "6.4.0-rc.7", want: "6.3.2"}, + {version: "6.4.0-rc.8", want: "6.3.2"}, } for _, test := range tests { @@ -379,7 +380,7 @@ func TestInstallDockerProofTracksPrereleaseContract(t *testing.T) { "The active prerelease `v"+version+"` cut sets the repo-root `VERSION`, repo-root `docker-compose.yml` image default, `scripts/install-docker.sh` fallback, and Helm chart release metadata to the same `"+version+"` release version.", comparisonLine, "This prerelease keeps `rollback_version=v"+previous+"`, publishes a versioned public GitHub prerelease plus versioned Docker and Helm artifacts, and does not move stable/latest install pointers or stable semver aliases.", - "The changes since `v"+comparisonVersion+"` add the canonical `alert_fired` mobile push type, but preserve the existing `view_alert` navigation action and all route, request/response, pairing, and authorization contracts.", + "add the canonical `alert_fired` mobile push type, but preserve the existing `view_alert` navigation action and all route, request/response, pairing, and authorization contracts.", "Published Pulse Mobile iOS build 12 and Android versionCode 9 already route `action_type=view_alert`, so the server cut is classified `existing-mobile-build-compatible`; no companion upload or public mobile-store rollout is part of this candidate.", "The prerelease Windows path retains exact-SHA, checksum, and detached-signature verification without Authenticode. Stable `v"+stableTarget+"` also skips SignPath under the standing unavailable policy", "For the active prerelease `v"+version+"` cut, the repo-root compose default and `scripts/install-docker.sh` fallback must both pin `"+version+"` until the next governed stable cut moves them forward.",