fix(agent): sharpen autopilot_profile_missing wording to assignment gap

Sessions only exist after the backend's device-registration validation
(Autopilot S/N or Corporate Identifier via Graph) passed, so a device
with ProfileAvailable=0 is known to the tenant — the actual gap is the
deployment-profile ASSIGNMENT (not assigned, or still propagating when
the user went through OOBE), not the registration. Reword agent event,
UI callout, and MCP field docs accordingly; likelyCauses now
profile_not_assigned/profile_assignment_not_propagated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-07-16 17:30:51 +02:00
parent 95126876ac
commit bfdcf3694d
4 changed files with 16 additions and 12 deletions
@@ -287,16 +287,18 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Telemetry.DeviceInfo
EmitDeviceInfoEvent(Constants.EventTypes.AutopilotProfile, "Autopilot profile configuration", data);
// ProfileAvailable=0 means the ZTD service returned no profile for this device
// during OOBE (not Autopilot-registered, profile assignment not propagated yet,
// or device deleted from Autopilot). Such a device still enrolls via manual
// Entra join + MDM auto-enrollment and would otherwise look like a regular
// during OOBE. Sessions only exist after the backend's device-registration
// validation passed, so the device itself is typically known to the tenant —
// what was missing is the deployment-profile ASSIGNMENT (not assigned, or
// still propagating/'assigning' when the user went through OOBE). OOBE then
// runs as a standard Entra join and would otherwise look like a regular
// Autopilot session — surface the edge case explicitly.
if (IsAutopilotProfileMissing(data))
{
var missingData = new Dictionary<string, object>
{
{ "profileAvailable", "0" },
{ "likelyCauses", "not_registered_in_autopilot,profile_assignment_not_propagated,deleted_from_autopilot" }
{ "likelyCauses", "profile_not_assigned,profile_assignment_not_propagated" }
};
if (TryExtractZeroTouchTenantDomain(data, out var ztdTenantDomain))
{
@@ -305,11 +307,11 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Telemetry.DeviceInfo
}
EmitDeviceInfoEvent(Constants.EventTypes.AutopilotProfileMissing,
"No Autopilot profile cached on this device (ProfileAvailable=0) — the device was likely not Autopilot-registered when OOBE ran; this enrollment appears to be a manual Entra ID join, not an Autopilot deployment.",
"No Autopilot profile was available during OOBE (ProfileAvailable=0) — most likely no deployment profile was assigned to the device, or the assignment had not finished propagating when OOBE ran. OOBE proceeded as a standard Entra ID join instead of an Autopilot deployment.",
missingData,
EventSeverity.Warning);
_logger.Warning("EnrollmentTracker: no Autopilot profile cached (ProfileAvailable=0) — non-Autopilot OOBE enrollment suspected");
_logger.Warning("EnrollmentTracker: no Autopilot profile available during OOBE (ProfileAvailable=0) — deployment profile not assigned or assignment not yet propagated");
}
// Emit dedicated enrollment_type_detected event for easy filtering. Routed through
@@ -1 +1 @@
1344
1345
@@ -261,7 +261,7 @@ export const DEVICE_PROPERTIES_CATALOG = {
autopilot_profile_missing: {
'autopilot_profile_missing.profileAvailable': { type: 'string', description: 'Always "0" — Windows recorded that no Autopilot profile was available during OOBE' },
'autopilot_profile_missing.zeroTouchTenantDomain': { type: 'string', description: 'CloudAssignedTenantDomain from the cached ZeroTouchConfig (empty when no profile was downloaded)' },
'autopilot_profile_missing.likelyCauses': { type: 'string', description: 'Comma-separated candidate causes (not_registered_in_autopilot, profile_assignment_not_propagated, deleted_from_autopilot)' },
'autopilot_profile_missing.likelyCauses': { type: 'string', description: 'Comma-separated candidate causes (profile_not_assigned, profile_assignment_not_propagated) — the device itself passed backend device-registration validation, so the gap is the profile assignment, not the registration' },
},
hardware_spec: {
'hardware_spec.cpuName': { type: 'string', description: 'CPU model name (e.g. "Intel Core i7-1265U")' },
@@ -391,10 +391,12 @@ export default function DeviceDetailsCard({ events, latestAgentVersion }: { even
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
</svg>
<span>
<span className="font-semibold">No Autopilot profile found on this device.</span>{" "}
It was likely not registered for Windows Autopilot when OOBE ran — this
enrollment appears to be a manual Entra ID join during OOBE, not an
Autopilot deployment.
<span className="font-semibold">No Autopilot profile was applied during OOBE.</span>{" "}
The Autopilot service returned no profile for this device when OOBE ran —
most likely no deployment profile was assigned to the device, or the
assignment was still propagating (&quot;assigning&quot;) and the user went
through OOBE before it arrived. The enrollment therefore ran as a standard
Entra ID join instead of an Autopilot deployment.
</span>
</div>
</div>