feat(telemetry): observe V1 compatibility paths safely

This commit is contained in:
m
2026-08-30 10:25:35 +03:00
parent a0b742b1d5
commit 3efcbbded8
7 changed files with 198 additions and 1 deletions
+77
View File
@@ -0,0 +1,77 @@
// Package telemetry contains operational projections that do not own domain
// state. Compatibility events are intentionally redacted and best-effort.
package telemetry
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log"
"strconv"
"time"
)
// CompatibilityEvent is one bounded invocation observation. Aggregators can
// derive counts and unique request/session counts from the redacted keys.
// It deliberately contains no content, secret, or user identifier.
type CompatibilityEvent struct {
Event string `json:"event"`
Path string `json:"path"`
Component string `json:"component"`
Access string `json:"access"`
Reason string `json:"reason"`
Gen2PathAvailable bool `json:"gen2_path_available"`
Fallback bool `json:"fallback"`
Primary bool `json:"primary"`
Outcome string `json:"outcome"`
InvocationCount int `json:"invocation_count"`
UniqueRequestKey string `json:"unique_request_key"`
UniqueSessionKey string `json:"unique_session_key"`
SafeCorrelationID string `json:"correlation_id"`
LastUsedAt string `json:"last_used_at"`
ObservedAtUnixMillis int64 `json:"observed_at_unix_millis"`
}
// NewCompatibilityEvent creates a redacted event. requestRef/sessionRef are
// hashed immediately; callers must pass identifiers only, never content.
func NewCompatibilityEvent(path, component, access, reason string, gen2PathAvailable, fallback, primary bool, outcome, requestRef, sessionRef string, now time.Time) CompatibilityEvent {
if now.IsZero() {
now = time.Now().UTC()
}
requestKey := digest(requestRef)
sessionKey := digest(sessionRef)
correlationInput := requestRef + "\x00" + sessionRef + "\x00" + path + "\x00" + strconv.FormatInt(now.UnixMilli(), 10)
return CompatibilityEvent{
Event: "compatibility_observation",
Path: path,
Component: component,
Access: access,
Reason: reason,
Gen2PathAvailable: gen2PathAvailable,
Fallback: fallback,
Primary: primary,
Outcome: outcome,
InvocationCount: 1,
UniqueRequestKey: requestKey,
UniqueSessionKey: sessionKey,
SafeCorrelationID: digest(correlationInput),
LastUsedAt: now.UTC().Format(time.RFC3339Nano),
ObservedAtUnixMillis: now.UnixMilli(),
}
}
// RecordCompatibility emits a structured redacted event. Telemetry is
// best-effort and cannot change the compatibility path's result.
func RecordCompatibility(path, component, access, reason string, gen2PathAvailable, fallback, primary bool, outcome, requestRef, sessionRef string, now time.Time) {
event := NewCompatibilityEvent(path, component, access, reason, gen2PathAvailable, fallback, primary, outcome, requestRef, sessionRef, now)
payload, err := json.Marshal(event)
if err != nil {
return
}
log.Printf("%s", payload)
}
func digest(value string) string {
sum := sha256.Sum256([]byte(value))
return hex.EncodeToString(sum[:8])
}
+20
View File
@@ -0,0 +1,20 @@
package telemetry
import (
"strings"
"testing"
"time"
)
func TestCompatibilityEventRedactsRequestAndSessionReferences(t *testing.T) {
event := NewCompatibilityEvent("personal-memory-fallback", "core-runtime", "read", "empty-gen2-projection", true, true, false, "SUCCESS", "request-secret-looking", "session-secret-looking", time.UnixMilli(42))
if event.InvocationCount != 1 || event.ObservedAtUnixMillis != 42 || event.LastUsedAt == "" {
t.Fatalf("event metadata incomplete: %+v", event)
}
if strings.Contains(event.UniqueRequestKey, "request-secret-looking") || strings.Contains(event.UniqueSessionKey, "session-secret-looking") || strings.Contains(event.SafeCorrelationID, "secret-looking") {
t.Fatalf("event leaked reference: %+v", event)
}
if event.Path != "personal-memory-fallback" || !event.Gen2PathAvailable || !event.Fallback || event.Primary {
t.Fatalf("event classification incorrect: %+v", event)
}
}