diff --git a/.claude/commands b/.claude/commands
index 9a799daf..a3970d47 160000
--- a/.claude/commands
+++ b/.claude/commands
@@ -1 +1 @@
-Subproject commit 9a799daf666d209a2c68498d88a650a450b875ae
+Subproject commit a3970d474c65afd4d2709a88704e6cc14f84f3d7
diff --git a/.gitignore b/.gitignore
index e4d4edca..f5611b6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,3 +118,7 @@ scripts/Deployment/build_and_upload_release_agent_build.ps1
TODO.txt
tools/orphan-analysis.py
tasks/todo.md
+
+# Azure Table cleanup backups (dry-run exports + delete manifests)
+# Produced by /cleanup-table skill — never commit deletion payloads
+db-backups/
diff --git a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Enrollment/EnrollmentTracker.CompletionLogic.cs b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Enrollment/EnrollmentTracker.CompletionLogic.cs
index 9b1e4ec3..42553058 100644
--- a/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Enrollment/EnrollmentTracker.CompletionLogic.cs
+++ b/src/Agent/AutopilotMonitor.Agent.Core/Monitoring/Enrollment/EnrollmentTracker.CompletionLogic.cs
@@ -1579,8 +1579,16 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Enrollment
/// detects a real AAD user join (non-placeholder) during the session. Updates
/// _aadJoinedWithUser atomically so subsequent WhiteGloveClassifier calls
/// correctly see the real user (driving IsDeviceOnlyDeployment to false and
- /// triggering the classifier's hard-exclude). Re-runs the completion guards.
+ /// triggering the classifier's hard-exclude).
///
+ ///
+ /// This is NOT a completion trigger. In a user-driven v1 flow the real AAD user
+ /// appears at the START of AccountSetup (when the user signs in), not at the end —
+ /// firing completion here would short-circuit ESP. The signal only flips classifier
+ /// state away from device-only/WhiteGlove; completion continues to flow through the
+ /// standard paths (ime_pattern / esp_hello_composite / desktop_hello), each of which
+ /// enforces its own ESP and Hello gates.
+ ///
public void NotifyAadUserJoinedLate(string userEmail)
{
bool alreadyJoined;
@@ -1609,7 +1617,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Enrollment
_statePersistence.Save(_stateData);
RecordSignal("aad_user_joined_late");
- _logger.Info($"EnrollmentTracker: late AAD user joined ({userEmail}) — re-evaluating completion");
+ _logger.Info($"EnrollmentTracker: late AAD user joined ({userEmail}) — classifier state updated");
var secondsSinceStart = (DateTime.UtcNow - _agentStartTimeUtc).TotalSeconds;
EmitTraceEvent("aad_user_joined_late",
@@ -1619,11 +1627,6 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Enrollment
{ "secondsSinceAgentStart", secondsSinceStart },
{ "userEmailDomain", userEmail?.Contains("@") == true ? userEmail.Substring(userEmail.IndexOf('@')) : "unknown" },
});
-
- // Re-evaluate guards with fresh AAD-joined state. The classifier will now hard-exclude
- // a WhiteGlove classification for this session; the standard enrollment_complete path
- // can now fire once Hello/desktop resolve.
- TryEmitEnrollmentComplete("aad_user_joined_late");
}
///
diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
index 4fba33e9..89a41372 100644
--- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
+++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
@@ -1 +1 @@
-1037
+1039