fix(agent): admin-friendly hello_policy_detection_mismatch wording

"detector bug suspected" confused customer admins and is factually
wrong since sessions 772fe502/1696e416 proved the usual cause: the
user-scoped WHfB CSP value flip-flops during User-ESP while Intune sync
is still writing, so even a twice-confirmed "disabled" read can be
stale by the time the wizard launches.

New message explains what happened and that enrollment tracking is
unaffected (live Hello events take precedence). Adds a likelyCause
data field; event type, severity and detection logic unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-07-13 11:15:03 +02:00
parent 108c52be5e
commit da7d663c3b
2 changed files with 13 additions and 7 deletions
@@ -197,8 +197,9 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Monitoring
public void HelloTerminalEvent_after_policy_disabled_emits_mismatch_warning()
{
// PR4: a Hello terminal arriving while the tracker still believes policy=disabled
// is a detector bug indicator. The tracker emits hello_policy_detection_mismatch
// before forwarding HelloCompleted.
// means the policy value was stale or changed during enrollment (sessions
// 772fe502/1696e416 — flip-flopping user-scoped WHfB CSP). The tracker emits
// hello_policy_detection_mismatch before forwarding HelloCompleted.
using var f = new Fixture();
f.Tracker.SetPolicyForTest(helloEnabled: false, source: "CSP/Intune");
@@ -397,7 +398,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Tests.Monitoring
public void HelloTerminalEvent_when_policy_unknown_does_not_emit_mismatch()
{
// Policy never detected → mismatch must NOT fire (we don't know whether to expect
// Hello or not, so the arrival is not evidence of a detector bug).
// Hello or not, so the arrival proves nothing about the policy value).
using var f = new Fixture();
// Deliberately skip SetPolicyForTest so _isPolicyConfigured stays false.
@@ -703,9 +703,13 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
}
// PR4 (882fef64 debrief) — emit a warning when a Hello-terminal event arrives while
// policy is explicitly disabled. This indicates a bug in the CSP/GPO detector — the
// device clearly DOES have Hello-for-Business in some form, despite our reader saying
// otherwise. Severity Warning + Phase Unknown so the event surfaces in dashboards but
// policy is explicitly disabled. Originally worded "detector bug suspected"; sessions
// 772fe502/1696e416 (2026-07-13) proved the real cause is usually the POLICY VALUE
// itself: the user-scoped WHfB CSP flip-flops during User-ESP while Intune sync is
// still writing, so even a twice-confirmed "disabled" read can be stale by the time
// the wizard launches. The message is written for customer admins — it explains that
// the live Hello events win and the enrollment is unaffected, without blaming our own
// detector. Severity Warning + Phase Unknown so the event surfaces in dashboards but
// doesn't claim to be a lifecycle marker.
private void EmitHelloPolicyDetectionMismatch(string actualEventType, int? windowsEventId, DateTime timestamp)
{
@@ -723,6 +727,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
{ "expected", "no_hello" },
{ "actual", actualEventType ?? string.Empty },
{ "policySource", "tracker_state" },
{ "likelyCause", "whfb_policy_value_stale_or_changed_during_enrollment" },
};
if (windowsEventId.HasValue) data["windowsEventId"] = windowsEventId.Value;
@@ -735,7 +740,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Enrollment.SystemSignals
Severity = EventSeverity.Warning,
Source = source,
Phase = EnrollmentPhase.Unknown,
Message = $"Hello policy detected as DISABLED but Hello terminal event '{actualEventType}' arrived — detector bug suspected.",
Message = $"Windows Hello activity ('{actualEventType}') observed although the WHfB policy on this device read 'disabled' — the policy value was stale or changed during enrollment. The actual Hello events take precedence; enrollment tracking is unaffected.",
Data = data,
ImmediateUpload = true,
});