**Goal:** Free the paid M365 seat by removing assigned SKU(s). **Tasks:** * [ ] Research licensing (block sign-in vs remove license). * [ ] Identify Graph API calls to **remove user licenses (SKU IDs)**. * [ ] Input: `user_principal_name` * [ ] Steps: resolve → list assigned licenses → remove SKUs. * [ ] Verify seat released (license assignment delta). * [ ] Emit audit JSON (SKUs removed, correlationId). **Acceptance:** * Dry-run mode. * Idempotent. * Unit tests with mocked Graph API.
Goal: Free the paid M365 seat by removing assigned SKU(s).
Tasks:
Research licensing (block sign-in vs remove license).
Identify Graph API calls to remove user licenses (SKU IDs).
Input:
user_principal_nameSteps: resolve → list assigned licenses → remove SKUs.
Verify seat released (license assignment delta).
Emit audit JSON (SKUs removed, correlationId).
Acceptance:
Dry-run mode.
Idempotent.
Unit tests with mocked Graph API.