mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Complete schema 14 privacy disclosure
Name every outbound alert-quality field in both operator-facing privacy documents, lock the current schema value in verification, and align the alert-manager adoption test with the telemetry contract. Change-source: pulse-maintainer
This commit is contained in:
+22
-9
@@ -37,7 +37,7 @@ Every field is listed below with the reason it exists. Nothing else is included
|
||||
|
||||
| Field | Example | Purpose |
|
||||
|-------|---------|---------|
|
||||
| Schema version | `13` | Identify the exact payload contract so old and new signals are not mixed silently |
|
||||
| Schema version | `14` | Identify the exact payload contract so old and new signals are not mixed silently |
|
||||
| Sent at | `2026-07-23T08:30:00Z` | Date the individual heartbeat without sending a history of client activity |
|
||||
| Install ID | `a1b2c3d4-...` | Distinguish active installations within one rotation window without tying telemetry to an account or person |
|
||||
| Version | `6.0.0-rc.1` | Track the canonical release identity currently deployed |
|
||||
@@ -93,17 +93,30 @@ Every field is listed below with the reason it exists. Nothing else is included
|
||||
| Alerts fired 30d | `18` | Count unique locally retained alert occurrences in the current 30-day window without sending alert text, resource IDs, or timestamps |
|
||||
| Alerts acknowledged 30d | `7` | Count acknowledgements in the current 30-day window without sending actors, reasons, alert IDs, or timestamps |
|
||||
| Alerts resolved 30d | `12` | Count resolved alert records in the current 30-day window without sending resolution details, alert IDs, or resource IDs |
|
||||
| Active alerts by severity | `1` info, `2` warning, `1` critical | Three aggregate counts that reconcile to active alerts |
|
||||
| Active alert age buckets | `1` under 1h, `2` 1h-24h, `1` 1d-7d, `0` 7d+ | Four closed age buckets with no alert timestamps |
|
||||
| Alerts fired by severity 30d | `2` info, `10` warning, `6` critical | Three aggregate occurrence counts that reconcile to alerts fired 30d |
|
||||
| Alerts resolved by severity 30d | `1` info, `7` warning, `4` critical | Three aggregate occurrence counts that reconcile to alerts resolved 30d |
|
||||
| Alert resolution duration buckets 30d | `3` under 15m, `2` 15m-1h, `5` 1h-24h, `2` 1d-7d, `0` 7d+ | Five closed time-to-resolution buckets with no occurrence timestamps |
|
||||
| Repeat alert occurrences 30d | `4` | Count occurrences after the first local occurrence of the same canonical alert identity, without sending that identity |
|
||||
| Snoozed alert occurrences 30d | `3` | Count occurrences with a durable suppression lifecycle transition |
|
||||
| Active alerts info | `1` | Count currently active info alerts without sending alert content or identity |
|
||||
| Active alerts warning | `2` | Count currently active warning alerts without sending alert content or identity |
|
||||
| Active alerts critical | `1` | Count currently active critical alerts without sending alert content or identity |
|
||||
| Active alerts age under 1h | `1` | Count active alerts in the closed under-one-hour age bucket without sending timestamps |
|
||||
| Active alerts age 1h 24h | `2` | Count active alerts in the closed one-hour-to-one-day age bucket without sending timestamps |
|
||||
| Active alerts age 1d 7d | `1` | Count active alerts in the closed one-day-to-seven-day age bucket without sending timestamps |
|
||||
| Active alerts age 7d plus | `0` | Count active alerts in the closed seven-days-or-more age bucket without sending timestamps |
|
||||
| Alerts fired info 30d | `2` | Count info alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts fired warning 30d | `10` | Count warning alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts fired critical 30d | `6` | Count critical alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved info 30d | `1` | Count resolved info alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved warning 30d | `7` | Count resolved warning alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved critical 30d | `4` | Count resolved critical alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolution under 15m 30d | `3` | Count resolved occurrences in the closed under-15-minute duration bucket without sending timestamps |
|
||||
| Alerts resolution 15m 1h 30d | `2` | Count resolved occurrences in the closed 15-minute-to-one-hour duration bucket without sending timestamps |
|
||||
| Alerts resolution 1h 24h 30d | `5` | Count resolved occurrences in the closed one-hour-to-one-day duration bucket without sending timestamps |
|
||||
| Alerts resolution 1d 7d 30d | `2` | Count resolved occurrences in the closed one-day-to-seven-day duration bucket without sending timestamps |
|
||||
| Alerts resolution 7d plus 30d | `0` | Count resolved occurrences in the closed seven-days-or-more duration bucket without sending timestamps |
|
||||
| Alerts repeat occurrences 30d | `4` | Count occurrences after the first local occurrence of the same canonical alert identity, without sending that identity |
|
||||
| Alerts snoozed occurrences 30d | `3` | Count occurrences with a durable suppression lifecycle transition |
|
||||
| Alerts resolved while snoozed 30d | `2` | Count snoozed occurrences whose recovery transition arrived before an unsnooze transition |
|
||||
| Alert manager tenants | `2` | Denominator for tenant-level alert configuration and persistence fields |
|
||||
| Alert delivery active tenants | `2` | Count tenant alert managers with delivery enabled and activation state active |
|
||||
| Alert flapping detection enabled tenants | `2` | Count tenant alert managers with flapping detection configured, not detected flapping episodes |
|
||||
| Alert flapping enabled tenants | `2` | Count tenant alert managers with flapping detection configured, not detected flapping episodes |
|
||||
| Alert intent policy configured tenants | `1` | Count tenant alert managers with an explicitly revised default, resource-type, or resource intent policy |
|
||||
| Alert event history authoritative tenants | `2` | Count tenant alert managers whose durable event history is authoritative |
|
||||
| Alert active state authoritative tenants | `2` | Count tenant alert managers whose durable active-state projection is authoritative |
|
||||
|
||||
@@ -74,6 +74,10 @@ than accepting secret values.
|
||||
The canonical and shipped privacy documents must state this retained-data and
|
||||
telemetry boundary explicitly and remain byte-for-byte synchronized, so the
|
||||
promise visible inside the product cannot drift from the repository policy.
|
||||
Their telemetry table must identify the current schema version and name every
|
||||
outbound JSON field individually. Grouped prose may explain related aggregates,
|
||||
but it cannot replace field-level disclosure or make a newly added counter
|
||||
invisible to operators reviewing exactly what Pulse sends.
|
||||
|
||||
## Canonical Files
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ Every field is listed below with the reason it exists. Nothing else is included
|
||||
|
||||
| Field | Example | Purpose |
|
||||
|-------|---------|---------|
|
||||
| Schema version | `13` | Identify the exact payload contract so old and new signals are not mixed silently |
|
||||
| Schema version | `14` | Identify the exact payload contract so old and new signals are not mixed silently |
|
||||
| Sent at | `2026-07-23T08:30:00Z` | Date the individual heartbeat without sending a history of client activity |
|
||||
| Install ID | `a1b2c3d4-...` | Distinguish active installations within one rotation window without tying telemetry to an account or person |
|
||||
| Version | `6.0.0-rc.1` | Track the canonical release identity currently deployed |
|
||||
@@ -93,17 +93,30 @@ Every field is listed below with the reason it exists. Nothing else is included
|
||||
| Alerts fired 30d | `18` | Count unique locally retained alert occurrences in the current 30-day window without sending alert text, resource IDs, or timestamps |
|
||||
| Alerts acknowledged 30d | `7` | Count acknowledgements in the current 30-day window without sending actors, reasons, alert IDs, or timestamps |
|
||||
| Alerts resolved 30d | `12` | Count resolved alert records in the current 30-day window without sending resolution details, alert IDs, or resource IDs |
|
||||
| Active alerts by severity | `1` info, `2` warning, `1` critical | Three aggregate counts that reconcile to active alerts |
|
||||
| Active alert age buckets | `1` under 1h, `2` 1h-24h, `1` 1d-7d, `0` 7d+ | Four closed age buckets with no alert timestamps |
|
||||
| Alerts fired by severity 30d | `2` info, `10` warning, `6` critical | Three aggregate occurrence counts that reconcile to alerts fired 30d |
|
||||
| Alerts resolved by severity 30d | `1` info, `7` warning, `4` critical | Three aggregate occurrence counts that reconcile to alerts resolved 30d |
|
||||
| Alert resolution duration buckets 30d | `3` under 15m, `2` 15m-1h, `5` 1h-24h, `2` 1d-7d, `0` 7d+ | Five closed time-to-resolution buckets with no occurrence timestamps |
|
||||
| Repeat alert occurrences 30d | `4` | Count occurrences after the first local occurrence of the same canonical alert identity, without sending that identity |
|
||||
| Snoozed alert occurrences 30d | `3` | Count occurrences with a durable suppression lifecycle transition |
|
||||
| Active alerts info | `1` | Count currently active info alerts without sending alert content or identity |
|
||||
| Active alerts warning | `2` | Count currently active warning alerts without sending alert content or identity |
|
||||
| Active alerts critical | `1` | Count currently active critical alerts without sending alert content or identity |
|
||||
| Active alerts age under 1h | `1` | Count active alerts in the closed under-one-hour age bucket without sending timestamps |
|
||||
| Active alerts age 1h 24h | `2` | Count active alerts in the closed one-hour-to-one-day age bucket without sending timestamps |
|
||||
| Active alerts age 1d 7d | `1` | Count active alerts in the closed one-day-to-seven-day age bucket without sending timestamps |
|
||||
| Active alerts age 7d plus | `0` | Count active alerts in the closed seven-days-or-more age bucket without sending timestamps |
|
||||
| Alerts fired info 30d | `2` | Count info alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts fired warning 30d | `10` | Count warning alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts fired critical 30d | `6` | Count critical alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved info 30d | `1` | Count resolved info alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved warning 30d | `7` | Count resolved warning alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolved critical 30d | `4` | Count resolved critical alert occurrences in the current 30-day window without sending alert content or identity |
|
||||
| Alerts resolution under 15m 30d | `3` | Count resolved occurrences in the closed under-15-minute duration bucket without sending timestamps |
|
||||
| Alerts resolution 15m 1h 30d | `2` | Count resolved occurrences in the closed 15-minute-to-one-hour duration bucket without sending timestamps |
|
||||
| Alerts resolution 1h 24h 30d | `5` | Count resolved occurrences in the closed one-hour-to-one-day duration bucket without sending timestamps |
|
||||
| Alerts resolution 1d 7d 30d | `2` | Count resolved occurrences in the closed one-day-to-seven-day duration bucket without sending timestamps |
|
||||
| Alerts resolution 7d plus 30d | `0` | Count resolved occurrences in the closed seven-days-or-more duration bucket without sending timestamps |
|
||||
| Alerts repeat occurrences 30d | `4` | Count occurrences after the first local occurrence of the same canonical alert identity, without sending that identity |
|
||||
| Alerts snoozed occurrences 30d | `3` | Count occurrences with a durable suppression lifecycle transition |
|
||||
| Alerts resolved while snoozed 30d | `2` | Count snoozed occurrences whose recovery transition arrived before an unsnooze transition |
|
||||
| Alert manager tenants | `2` | Denominator for tenant-level alert configuration and persistence fields |
|
||||
| Alert delivery active tenants | `2` | Count tenant alert managers with delivery enabled and activation state active |
|
||||
| Alert flapping detection enabled tenants | `2` | Count tenant alert managers with flapping detection configured, not detected flapping episodes |
|
||||
| Alert flapping enabled tenants | `2` | Count tenant alert managers with flapping detection configured, not detected flapping episodes |
|
||||
| Alert intent policy configured tenants | `1` | Count tenant alert managers with an explicitly revised default, resource-type, or resource intent policy |
|
||||
| Alert event history authoritative tenants | `2` | Count tenant alert managers whose durable event history is authoritative |
|
||||
| Alert active state authoritative tenants | `2` | Count tenant alert managers whose durable active-state projection is authoritative |
|
||||
|
||||
@@ -157,13 +157,11 @@ func TestBranchcov0723Am_AccumulateInstallOutcomeCounts(t *testing.T) {
|
||||
assert.Equal(t, sentryCounts(), counts)
|
||||
})
|
||||
|
||||
t.Run("alert_manager_with_empty_history_increments_nothing", func(t *testing.T) {
|
||||
t.Run("alert_manager_with_empty_history_reports_configuration_adoption", func(t *testing.T) {
|
||||
// Covers the alertManager != nil true-arm. A freshly-constructed alert
|
||||
// manager has no history, so GetAlertHistorySince returns nothing and
|
||||
// no alert-outcome counts accrue. (Deeper history-driven counting is
|
||||
// exercised directly on accumulateAlertOutcomeCounts above; history
|
||||
// cannot be injected into an alerts.Manager from outside the alerts
|
||||
// package without driving the full evaluation pipeline.)
|
||||
// manager has no history, so no lifecycle outcome counts accrue. It does
|
||||
// still contribute one manager and its default-enabled flapping posture;
|
||||
// those are configuration adoption denominators rather than outcomes.
|
||||
alertMgr := alerts.NewManagerWithDataDir(t.TempDir())
|
||||
defer alertMgr.Stop()
|
||||
|
||||
@@ -172,7 +170,10 @@ func TestBranchcov0723Am_AccumulateInstallOutcomeCounts(t *testing.T) {
|
||||
|
||||
counts := sentryCounts()
|
||||
accumulateInstallOutcomeCounts(&counts, mon, now)
|
||||
assert.Equal(t, sentryCounts(), counts, "empty history must not change any count")
|
||||
expected := sentryCounts()
|
||||
expected.AlertQuality.ManagerTenants = 1
|
||||
expected.AlertQuality.FlappingEnabledTenants = 1
|
||||
assert.Equal(t, expected, counts, "empty history must only add configuration adoption")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package telemetry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
@@ -335,57 +336,57 @@ func TestApplySnapshot(t *testing.T) {
|
||||
|
||||
snap := func() Snapshot {
|
||||
return Snapshot{
|
||||
PVENodes: 3,
|
||||
VMs: 10,
|
||||
Containers: 5,
|
||||
AgentHosts: 2,
|
||||
DockerContainers: 12,
|
||||
KubernetesPods: 18,
|
||||
StoragePools: 4,
|
||||
PhysicalDisks: 9,
|
||||
TrueNASSystems: 1,
|
||||
TrueNASApps: 3,
|
||||
VMwareHosts: 2,
|
||||
AvailabilityTargets: 6,
|
||||
AIEnabled: true,
|
||||
PatrolEnabled: true,
|
||||
DiscoveryEnabled: true,
|
||||
NotificationsEnabled: true,
|
||||
AIActionsEnabled: true,
|
||||
AlertAIEnabled: true,
|
||||
ActiveAlerts: 2,
|
||||
PaidLicense: true,
|
||||
HasAPITokens: true,
|
||||
RBACCustomRoles: 3,
|
||||
RBACUserAssignments: 7,
|
||||
AuditReads30d: 41,
|
||||
ReportSchedules: 5,
|
||||
ReportSchedulesEnabled: 4,
|
||||
ReportSchedulesRun30d: 2,
|
||||
AgentProfiles: 9,
|
||||
UpdateAttempts30d: 4,
|
||||
UpdateSuccesses30d: 2,
|
||||
UpdateFailures30d: 1,
|
||||
UpdateLastFailureCategory: "download",
|
||||
ActiveAlertsCritical: 2,
|
||||
ActiveAlertsAge1h24h: 2,
|
||||
AlertsFiredCritical30d: 5,
|
||||
AlertsResolvedCritical30d: 3,
|
||||
AlertsResolution1h24h30d: 3,
|
||||
AlertsRepeatOccurrences30d: 2,
|
||||
AlertsSnoozedOccurrences30d: 2,
|
||||
AlertsResolvedWhileSnoozed30d: 1,
|
||||
AlertManagerTenants: 2,
|
||||
AlertDeliveryActiveTenants: 1,
|
||||
AlertFlappingEnabledTenants: 2,
|
||||
AlertIntentPolicyConfiguredTenants: 1,
|
||||
AlertEventHistoryAuthoritativeTenants: 2,
|
||||
AlertActiveStateAuthoritativeTenants: 2,
|
||||
PulseIntelligenceLoopConfigured: true,
|
||||
PulseIntelligenceLoopActive30d: true,
|
||||
PulseIntelligenceCompleteOperationsLoop30d: true,
|
||||
PulseIntelligenceApprovedExecutionLoop30d: true,
|
||||
PulseIntelligenceResolvedOperationsLoop30d: true,
|
||||
PVENodes: 3,
|
||||
VMs: 10,
|
||||
Containers: 5,
|
||||
AgentHosts: 2,
|
||||
DockerContainers: 12,
|
||||
KubernetesPods: 18,
|
||||
StoragePools: 4,
|
||||
PhysicalDisks: 9,
|
||||
TrueNASSystems: 1,
|
||||
TrueNASApps: 3,
|
||||
VMwareHosts: 2,
|
||||
AvailabilityTargets: 6,
|
||||
AIEnabled: true,
|
||||
PatrolEnabled: true,
|
||||
DiscoveryEnabled: true,
|
||||
NotificationsEnabled: true,
|
||||
AIActionsEnabled: true,
|
||||
AlertAIEnabled: true,
|
||||
ActiveAlerts: 2,
|
||||
PaidLicense: true,
|
||||
HasAPITokens: true,
|
||||
RBACCustomRoles: 3,
|
||||
RBACUserAssignments: 7,
|
||||
AuditReads30d: 41,
|
||||
ReportSchedules: 5,
|
||||
ReportSchedulesEnabled: 4,
|
||||
ReportSchedulesRun30d: 2,
|
||||
AgentProfiles: 9,
|
||||
UpdateAttempts30d: 4,
|
||||
UpdateSuccesses30d: 2,
|
||||
UpdateFailures30d: 1,
|
||||
UpdateLastFailureCategory: "download",
|
||||
ActiveAlertsCritical: 2,
|
||||
ActiveAlertsAge1h24h: 2,
|
||||
AlertsFiredCritical30d: 5,
|
||||
AlertsResolvedCritical30d: 3,
|
||||
AlertsResolution1h24h30d: 3,
|
||||
AlertsRepeatOccurrences30d: 2,
|
||||
AlertsSnoozedOccurrences30d: 2,
|
||||
AlertsResolvedWhileSnoozed30d: 1,
|
||||
AlertManagerTenants: 2,
|
||||
AlertDeliveryActiveTenants: 1,
|
||||
AlertFlappingEnabledTenants: 2,
|
||||
AlertIntentPolicyConfiguredTenants: 1,
|
||||
AlertEventHistoryAuthoritativeTenants: 2,
|
||||
AlertActiveStateAuthoritativeTenants: 2,
|
||||
PulseIntelligenceLoopConfigured: true,
|
||||
PulseIntelligenceLoopActive30d: true,
|
||||
PulseIntelligenceCompleteOperationsLoop30d: true,
|
||||
PulseIntelligenceApprovedExecutionLoop30d: true,
|
||||
PulseIntelligenceResolvedOperationsLoop30d: true,
|
||||
PulseIntelligencePatrolControlCompletedOperationsLoop30d: true,
|
||||
PulseIntelligencePatrolControlResolvedOperationsLoop30d: true,
|
||||
PulseIntelligencePatrolControlPaidCompletedOperationsLoop30d: true,
|
||||
@@ -697,6 +698,10 @@ func TestAllTelemetryFieldsAreDisclosed(t *testing.T) {
|
||||
t.Fatalf("read %s: %v", relativePath, err)
|
||||
}
|
||||
doc := normalizedTelemetryDisclosureTableText(string(raw))
|
||||
schemaDisclosure := fmt.Sprintf("schema version %d", TelemetrySchemaVersion)
|
||||
if !strings.Contains(doc, schemaDisclosure) {
|
||||
t.Errorf("%s must identify the current telemetry contract as %q", relativePath, schemaDisclosure)
|
||||
}
|
||||
for _, label := range fieldLabels {
|
||||
if !strings.Contains(doc, label) {
|
||||
t.Errorf("%s must disclose telemetry field %q", relativePath, label)
|
||||
|
||||
Reference in New Issue
Block a user