Files
pulse/pkg/server/telemetry_node_test_tally.go
rcourtman 9e37d629ac Measure node connection test outcomes
Telemetry could see only saved connections, so an install that tried to
reach a node and could not was indistinguishable from one that never
opened the add-node dialog. Both report zero configured connections and
stall at the same activation stage. Fleet data shows that population is
real and concentrated three to one in container deployments, and nothing
recorded whether those installs attempted a connection at all.

Record node connection test attempts and failures in a bounded,
day-bucketed tally in the config directory, pruned to a 31-day retention
window, and report both over the install-ID rotation window as
node_test_attempts_30d and node_test_failures_30d.

Recording starts only once a request carries a target and credentials, so
an incomplete form is never counted as a node that could not be reached.
A host string that turns out to be unusable does count, because the
attempt was made and it failed. Only the add-node dialog endpoint is
instrumented: instrumenting the unused test-config endpoint as well would
double-count a single operator action.

The tally holds counts alone. Hosts, credentials, and error text never
enter it, which is why it is plain JSON rather than encrypted history.
2026-08-24 10:17:17 +01:00

36 lines
1.2 KiB
Go

package server
import (
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/rcourtman/pulse-go-rewrite/internal/telemetry"
)
// applyNodeTestTelemetrySnapshot adds content-free node connection test counts
// from the local tally.
//
// ConfiguredConnections reports only connections that were saved, so without
// these an install that tried to reach a node and could not is indistinguishable
// from one that never opened the add-node dialog: both report zero connections
// and stall at the "secured" activation stage.
//
// The window is the shared install-ID rotation window, the same one the
// Pulse Intelligence counters use, so no counter outlives the pseudonymous
// identifier it is reported against.
func applyNodeTestTelemetrySnapshot(snap *telemetry.Snapshot, persistence *config.ConfigPersistence, now time.Time) {
if snap == nil || persistence == nil {
return
}
if now.IsZero() {
now = time.Now()
}
tally, err := persistence.LoadNodeTestTally()
if err != nil || tally == nil {
return
}
since := now.UTC().Add(-telemetry.PulseIntelligenceTelemetryWindow)
snap.NodeTestAttempts30d = tally.AttemptsSince(since)
snap.NodeTestFailures30d = tally.FailuresSince(since)
}