From d391900d6d5840ccf9be5ccce1d5981968ca0c2a Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Tue, 14 Apr 2026 14:55:05 +0200 Subject: [PATCH] added stateMachine discrepancy check events for further validation of stateMachine and upcoming final switch --- .../Monitoring/Tracking/EnrollmentTracker.cs | 66 +++++++++++++++++++ .../AutopilotMonitor.Agent/buildcounter.txt | 2 +- .../AutopilotMonitor.Shared/Constants.cs | 3 + 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/EnrollmentTracker.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/EnrollmentTracker.cs index fb0f0fad..b2d550b4 100644 --- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/EnrollmentTracker.cs +++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Tracking/EnrollmentTracker.cs @@ -53,6 +53,9 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking private bool _isWaitingForHello = false; // Track if we're waiting for Hello to complete before sending enrollment_complete private readonly bool _isBootstrapMode; // Agent started via bootstrap token (pre-MDM) private bool _sendTraceEvents = true; // Send Trace-severity events to backend for decision auditing + + // TEMPORARY: shadow SM rollout verification — remove when CompletionStateMachine is promoted to primary + private string _lastShadowDiscrepancySignature; private bool _enrollmentStartDeviceInfoCollected = false; // Re-collect enrollment-dependent info once at first ESP phase private bool _finalDeviceInfoCollected = false; // Ensure final device info is emitted only once private string _lastEmittedSummaryHash; // Track last emitted state-breakdown to avoid redundant summary events @@ -185,6 +188,11 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking _logger.Warning($"EnrollmentTracker [SHADOW DISCREPANCY]: trigger='{trigger}', " + $"shadowState={_completionSm.CurrentState}, actualEmitted={actualTerminal}, " + $"shadowCompleted={shadowTerminal}"); + + // TEMPORARY: shadow SM rollout verification — remove when CompletionStateMachine is promoted to primary + // Emit a backend event (throttled to 1x per unique signature per session) so we can query + // mismatches without relying on client-side logs. Severity=Warning so it ships independent of SendTraceEvents. + EmitShadowDiscrepancyEvent(trigger, ctx, actualTerminal, shadowTerminal); } else if (result.Transitioned) { @@ -385,6 +393,64 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Tracking } } + // TEMPORARY: shadow SM rollout verification — remove when CompletionStateMachine is promoted to primary + /// + /// Emits a shadow_discrepancy event when the shadow CompletionStateMachine disagrees + /// with the actual _enrollmentCompleteEmitted flag. Throttled to one event per unique + /// {trigger|shadowState|actualEmitted} signature per session to avoid flooding the backend + /// while still surfacing every distinct divergence constellation. + /// + private void EmitShadowDiscrepancyEvent(string trigger, CompletionContext ctx, bool actualTerminal, bool shadowTerminal) + { + var shadowState = _completionSm.CurrentState.ToString(); + var signature = $"{trigger}|{shadowState}|{actualTerminal}"; + if (signature == _lastShadowDiscrepancySignature) + return; + _lastShadowDiscrepancySignature = signature; + + var data = new Dictionary + { + { "trigger", trigger ?? "(null)" }, + { "shadowState", shadowState }, + { "actualEmitted", actualTerminal }, + { "shadowCompleted", shadowTerminal }, + { "enrollmentType", ctx?.EnrollmentType }, + { "autopilotMode", ctx?.AutopilotMode }, + { "skipUserStatusPage", ctx?.SkipUserStatusPage }, + { "aadJoinedWithUser", ctx?.AadJoinedWithUser ?? false }, + { "isHybridJoin", ctx?.IsHybridJoin ?? false }, + { "isDeviceOnly", ctx?.IsDeviceOnly ?? false }, + { "espEverSeen", ctx?.EspEverSeen ?? false }, + { "espFinalExitSeen", ctx?.EspFinalExitSeen ?? false }, + { "desktopArrived", ctx?.DesktopArrived ?? false }, + { "lastEspPhase", ctx?.LastEspPhase }, + { "hasHelloTracker", ctx?.HasHelloTracker ?? false }, + { "isHelloCompleted", ctx?.IsHelloCompleted ?? false }, + { "isHelloPolicyConfigured", ctx?.IsHelloPolicyConfigured ?? false }, + { "hasUnresolvedEspCategories", ctx?.HasUnresolvedEspCategories ?? false } + }; + + try + { + _emitEvent(new EnrollmentEvent + { + SessionId = _sessionId, + TenantId = _tenantId, + EventType = Constants.EventTypes.ShadowDiscrepancy, + Severity = EventSeverity.Warning, + Source = "EnrollmentTracker", + Phase = EnrollmentPhase.Unknown, + Message = $"Shadow SM mismatch: trigger={trigger}, shadow={shadowState}, emitted={actualTerminal}", + Data = data + }); + } + catch (Exception ex) + { + // Diagnostic event must never crash the agent + _logger.Debug($"EnrollmentTracker [SHADOW EVENT ERROR]: {ex.Message}"); + } + } + /// /// Starts the enrollment tracker: collects device info and starts IME log tracking. /// diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt index a8ed109d..07eafa38 100644 --- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt +++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt @@ -1 +1 @@ -953 +956 diff --git a/src/Shared/AutopilotMonitor.Shared/Constants.cs b/src/Shared/AutopilotMonitor.Shared/Constants.cs index fb734fcf..76caeef8 100644 --- a/src/Shared/AutopilotMonitor.Shared/Constants.cs +++ b/src/Shared/AutopilotMonitor.Shared/Constants.cs @@ -200,6 +200,9 @@ namespace AutopilotMonitor.Shared public const string ModernDeploymentLog = "modern_deployment_log"; // Info-level live capture public const string ModernDeploymentWarning = "modern_deployment_warning"; // Level 3 (Warning) public const string ModernDeploymentError = "modern_deployment_error"; // Level 1-2 (Critical/Error) + + // TEMPORARY: shadow SM rollout verification — remove when CompletionStateMachine is promoted to primary + public const string ShadowDiscrepancy = "shadow_discrepancy"; } // -----------------------------------------------------------------------