# Feature Specification: Driver Updates (WUfB Add-on) (018)

**Feature Branch**: `feat/018-driver-updates-wufb`  
**Created**: 2026-01-03  
**Status**: Implemented  
**Priority**: P1

## Context
TenantPilot already covers core Windows Update for Business (WUfB) objects like:
- Update Rings (`windowsUpdateRing`)
- Feature Update Profiles (`windowsFeatureUpdateProfile`)
- Quality Update Profiles (`windowsQualityUpdateProfile`)

This feature adds **Windows Driver Updates** coverage to the same Update Management area so driver rollout configuration can be inventoried, snapshotted, diffed, and restored safely.

## In Scope
- New policy type: `windowsDriverUpdateProfile`
- Inventory/sync: list driver update profiles from Microsoft Graph and store them as policies.
- Snapshot capture: full snapshot of the profile payload (and assignments where supported).
- Restore:
  - Preview/dry-run with diff + risk checks.
  - Execution (PATCH/POST) as allowed by Graph, with audit logging.
- UI: normalized settings display (readable, admin-focused).

## Out of Scope (v1)
- Per-driver approval workflows / driver inventory insights.
- Advanced reporting on driver compliance.
- Partial per-setting restore.

## Graph API Details (confirmed)
- **Resource**: `deviceManagement/windowsDriverUpdateProfiles`
- **@odata.type**: `#microsoft.graph.windowsDriverUpdateProfile`
- **Patchable fields**: `displayName`, `description`, `approvalType`, `deploymentDeferralInDays`, `roleScopeTagIds`
- **Read-only fields (strip on PATCH)**: `deviceReporting`, `newUpdates`, `inventorySyncStatus`, `createdDateTime`, `lastModifiedDateTime`
- **Assignments**:
  - list: `/deviceManagement/windowsDriverUpdateProfiles/{id}/assignments`
  - assign action: `/deviceManagement/windowsDriverUpdateProfiles/{id}/assign`
  - update/delete: `/deviceManagement/windowsDriverUpdateProfiles/{id}/assignments/{assignmentId}`

## User Scenarios & Testing

### User Story 1 — Inventory + readable view (P1)
As an admin, I can see Windows Driver Update profiles in the Policies list and view their configuration in a readable way.

**Acceptance**
1. Driver update profiles appear in the policy inventory with the correct type and category.
2. Policy detail shows a normalized settings table (not only raw JSON).
3. Policy Versions render “Normalized settings” consistently.

### User Story 2 — Snapshot capture (P1)
As an admin, when I capture a version or add a driver update profile to a backup set, the snapshot contains all relevant settings.

**Acceptance**
1. Snapshot stores the full Graph payload in JSON (immutable).
2. Any non-patchable/read-only properties are still preserved in the snapshot (but not sent on restore).

### User Story 3 — Restore preview + execution (P1)
As an admin, I can restore a driver update profile from a snapshot with a clear preview and safe execution.

**Acceptance**
1. Preview shows what would change and blocks if risk checks fail.
2. Execution applies only patchable properties (contract-driven sanitization).
3. Restore results include Graph error details (request-id, client-request-id, path/method) on failure.

## Requirements

### Functional Requirements
- **FR-001**: Add `windowsDriverUpdateProfile` to `config/tenantpilot.php` with category “Update Management”.
- **FR-002**: Add Graph contract entry for `windowsDriverUpdateProfile` in `config/graph_contracts.php` (resource, type family, create/update methods, assignments paths).
- **FR-003**: Ensure `PolicySyncService` syncs driver update profiles via config-driven type list.
- **FR-004**: Ensure `PolicySnapshotService` captures a complete payload for this type.
- **FR-005**: Ensure `RestoreService` applies snapshots using contract-driven sanitization and audit logging.
- **FR-006**: Add normalized display support for the key driver update profile fields.
- **FR-007**: Add automated Pest tests for sync + snapshot + restore preview/execution.

### Non-Functional Requirements
- **NFR-001**: Preserve tenant isolation and least privilege.
- **NFR-002**: Keep restore safe-by-default (preview/confirmation/audit).
- **NFR-003**: No new external services or dependencies.
