// ----------------------------------------------------------------------------- // ReplayTelemetry.cs // Sprint: SPRINT_1227_0005_0004_BE_verdict_replay // Task: T10 — Telemetry for replay outcomes // ----------------------------------------------------------------------------- using System.Diagnostics; using System.Diagnostics.Metrics; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; namespace StellaOps.AuditPack.Services; /// /// OpenTelemetry instrumentation for verdict replay operations. /// Provides metrics, traces, and structured logging support. /// public sealed class ReplayTelemetry : IDisposable { /// /// Service name for telemetry identification. /// public const string ServiceName = "StellaOps.Replay"; /// /// Meter name for replay metrics. /// public const string MeterName = "StellaOps.Replay"; /// /// Activity source name for replay tracing. /// public const string ActivitySourceName = "StellaOps.Replay"; private readonly Meter _meter; // Counters private readonly Counter _replayExecutionsTotal; private readonly Counter _replayMatchesTotal; private readonly Counter _replayDivergencesTotal; private readonly Counter _replayErrorsTotal; private readonly Counter _attestationsGeneratedTotal; private readonly Counter _attestationsVerifiedTotal; private readonly Counter _eligibilityChecksTotal; // Histograms private readonly Histogram _replayDurationMs; private readonly Histogram _attestationGenerationDurationMs; private readonly Histogram _driftCount; private readonly Histogram _confidenceScore; // Gauges private readonly UpDownCounter _replaysInProgress; /// /// Activity source for distributed tracing. /// public static readonly ActivitySource ActivitySource = new(ActivitySourceName); /// /// Initializes a new instance of the ReplayTelemetry class. /// public ReplayTelemetry(IMeterFactory? meterFactory = null) { _meter = meterFactory?.Create(MeterName) ?? new Meter(MeterName); // Counters _replayExecutionsTotal = _meter.CreateCounter( "stellaops.replay.executions.total", unit: "{execution}", description: "Total number of replay executions"); _replayMatchesTotal = _meter.CreateCounter( "stellaops.replay.matches.total", unit: "{match}", description: "Total number of replay matches (verdict unchanged)"); _replayDivergencesTotal = _meter.CreateCounter( "stellaops.replay.divergences.total", unit: "{divergence}", description: "Total number of replay divergences detected"); _replayErrorsTotal = _meter.CreateCounter( "stellaops.replay.errors.total", unit: "{error}", description: "Total number of replay errors"); _attestationsGeneratedTotal = _meter.CreateCounter( "stellaops.replay.attestations.generated.total", unit: "{attestation}", description: "Total number of replay attestations generated"); _attestationsVerifiedTotal = _meter.CreateCounter( "stellaops.replay.attestations.verified.total", unit: "{verification}", description: "Total number of replay attestations verified"); _eligibilityChecksTotal = _meter.CreateCounter( "stellaops.replay.eligibility.checks.total", unit: "{check}", description: "Total number of replay eligibility checks"); // Histograms _replayDurationMs = _meter.CreateHistogram( "stellaops.replay.duration.ms", unit: "ms", description: "Replay execution duration in milliseconds"); _attestationGenerationDurationMs = _meter.CreateHistogram( "stellaops.replay.attestation.generation.duration.ms", unit: "ms", description: "Attestation generation duration in milliseconds"); _driftCount = _meter.CreateHistogram( "stellaops.replay.drift.count", unit: "{drift}", description: "Number of drifts detected per replay"); _confidenceScore = _meter.CreateHistogram( "stellaops.replay.eligibility.confidence", unit: "1", description: "Replay eligibility confidence score distribution"); // Gauges _replaysInProgress = _meter.CreateUpDownCounter( "stellaops.replay.in_progress", unit: "{replay}", description: "Number of replays currently in progress"); } #region Replay Execution Metrics /// /// Records the start of a replay execution. /// public void RecordReplayStarted(string manifestId, string scanId) { _replaysInProgress.Add(1, new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.ScanId, scanId } }); } /// /// Records the completion of a replay execution. /// public void RecordReplayCompleted( string manifestId, string scanId, ReplayOutcome outcome, int driftCount, TimeSpan duration) { var tags = new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.ScanId, scanId }, { ReplayTelemetryTags.Outcome, outcome.ToString().ToLowerInvariant() } }; _replaysInProgress.Add(-1, new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.ScanId, scanId } }); _replayExecutionsTotal.Add(1, tags); _replayDurationMs.Record(duration.TotalMilliseconds, tags); switch (outcome) { case ReplayOutcome.Match: _replayMatchesTotal.Add(1, tags); break; case ReplayOutcome.Divergence: _replayDivergencesTotal.Add(1, tags); _driftCount.Record(driftCount, tags); break; case ReplayOutcome.Error: _replayErrorsTotal.Add(1, tags); break; } } /// /// Records a replay error. /// public void RecordReplayError( string manifestId, string scanId, string errorCode) { var tags = new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.ScanId, scanId }, { ReplayTelemetryTags.ErrorCode, errorCode } }; _replaysInProgress.Add(-1, new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.ScanId, scanId } }); _replayErrorsTotal.Add(1, tags); } #endregion #region Attestation Metrics /// /// Records attestation generation. /// public void RecordAttestationGenerated( string manifestId, bool match, TimeSpan duration) { var tags = new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.Match, match.ToString().ToLowerInvariant() } }; _attestationsGeneratedTotal.Add(1, tags); _attestationGenerationDurationMs.Record(duration.TotalMilliseconds, tags); } /// /// Records attestation verification. /// public void RecordAttestationVerified( string attestationId, bool valid) { var tags = new TagList { { ReplayTelemetryTags.AttestationId, attestationId }, { ReplayTelemetryTags.Valid, valid.ToString().ToLowerInvariant() } }; _attestationsVerifiedTotal.Add(1, tags); } #endregion #region Eligibility Metrics /// /// Records an eligibility check. /// public void RecordEligibilityCheck( string manifestId, bool eligible, double confidenceScore) { var tags = new TagList { { ReplayTelemetryTags.ManifestId, manifestId }, { ReplayTelemetryTags.Eligible, eligible.ToString().ToLowerInvariant() } }; _eligibilityChecksTotal.Add(1, tags); _confidenceScore.Record(confidenceScore, tags); } #endregion #region Activity Helpers /// /// Starts an activity for replay execution. /// public static Activity? StartReplayActivity(string manifestId, string scanId) { var activity = ActivitySource.StartActivity("Replay.Execute"); activity?.SetTag(ReplayTelemetryTags.ManifestId, manifestId); activity?.SetTag(ReplayTelemetryTags.ScanId, scanId); return activity; } /// /// Starts an activity for attestation generation. /// public static Activity? StartAttestationActivity(string manifestId) { var activity = ActivitySource.StartActivity("Replay.GenerateAttestation"); activity?.SetTag(ReplayTelemetryTags.ManifestId, manifestId); return activity; } /// /// Starts an activity for eligibility check. /// public static Activity? StartEligibilityActivity(string manifestId) { var activity = ActivitySource.StartActivity("Replay.CheckEligibility"); activity?.SetTag(ReplayTelemetryTags.ManifestId, manifestId); return activity; } /// /// Starts an activity for divergence detection. /// public static Activity? StartDivergenceActivity(string manifestId) { var activity = ActivitySource.StartActivity("Replay.DetectDivergence"); activity?.SetTag(ReplayTelemetryTags.ManifestId, manifestId); return activity; } #endregion /// public void Dispose() { _meter.Dispose(); } } /// /// Tag names for replay telemetry. /// public static class ReplayTelemetryTags { public const string ManifestId = "manifest_id"; public const string ScanId = "scan_id"; public const string BundleId = "bundle_id"; public const string AttestationId = "attestation_id"; public const string Outcome = "outcome"; public const string Match = "match"; public const string Valid = "valid"; public const string Eligible = "eligible"; public const string ErrorCode = "error_code"; public const string DivergenceType = "divergence_type"; public const string DriftType = "drift_type"; public const string Severity = "severity"; } /// /// Replay outcome values. /// public enum ReplayOutcome { /// Verdict matched the original. Match, /// Divergence detected between original and replayed verdict. Divergence, /// Replay execution failed with error. Error, /// Replay was cancelled. Cancelled } /// /// Divergence severity levels. /// public static class DivergenceSeverities { public const string Critical = "critical"; public const string High = "high"; public const string Medium = "medium"; public const string Low = "low"; public const string Info = "info"; } /// /// Divergence type values. /// public static class DivergenceTypes { public const string VerdictDigest = "verdict_digest"; public const string Decision = "decision"; public const string Confidence = "confidence"; public const string Input = "input"; public const string Policy = "policy"; public const string Evidence = "evidence"; } /// /// Extension methods for adding replay telemetry. /// public static class ReplayTelemetryExtensions { /// /// Adds replay OpenTelemetry instrumentation. /// public static IServiceCollection AddReplayTelemetry(this IServiceCollection services) { services.TryAddSingleton(); return services; } }