# Implementation Report: Spec 419 - M365 TCM Workload Registry Expansion ## Preflight - Date: 2026-06-26 - Branch: `419-m365-tcm-workload-registry-expansion` - HEAD before implementation: `4aaec352 feat: add coverage v2 operator surface (#485)` - Dirty state before implementation: active `specs/419-m365-tcm-workload-registry-expansion/` artifacts were untracked; no unrelated tracked code changes were present. - Dirty state after implementation: expected Spec 419 code/test/spec artifacts only. - Activated skills/gates: - `spec-kit-implementation-loop`: active implementation workflow. - `.agent workflows/spec-readiness-gate`: PASS; spec, plan, tasks, and checklist existed with no blocking open questions. - `.agent repo-contracts/product-surface-gate`: PASS with existing-surface data impact. - `.agent temporary-migrations/tcm-cutover-guard`: PASS; no capture, restore, customer claim, or UI activation. - `pest-testing`: used for Pest 4 unit/feature/browser tests. - `browsertest`: used for focused existing-surface browser proof. - Dependency context: Specs 414, 415, 417, and 418 were read-only context and were not modified. - Stop conditions: none hit. ## Files Changed - `apps/platform/app/Support/TenantConfiguration/Workload.php` - `apps/platform/app/Services/TenantConfiguration/ResourceTypeRegistry.php` - `apps/platform/app/Services/TenantConfiguration/SupportedScopeResolver.php` - `apps/platform/app/Services/TenantConfiguration/ClaimGuard.php` - `apps/platform/database/migrations/2026_06_26_000419_expand_tenant_configuration_workloads.php` - `apps/platform/tests/Unit/Support/TenantConfiguration/CoverageKernelValueTest.php` - `apps/platform/tests/Unit/Support/TenantConfiguration/ResourceTypeRegistryTest.php` - `apps/platform/tests/Unit/Support/TenantConfiguration/Spec419M365WorkloadRegistryTest.php` - `apps/platform/tests/Unit/Support/TenantConfiguration/Spec419M365ClaimGuardTest.php` - `apps/platform/tests/Feature/TenantConfiguration/TenantConfigurationResourceTypeRegistryTest.php` - `apps/platform/tests/Feature/TenantConfiguration/TenantConfigurationSupportedScopeTest.php` - `apps/platform/tests/Feature/TenantConfiguration/Spec419M365RegistryExpansionTest.php` - `apps/platform/tests/Browser/Spec419M365RegistryOperatorSurfaceSmokeTest.php` - `specs/419-m365-tcm-workload-registry-expansion/tasks.md` - `specs/419-m365-tcm-workload-registry-expansion/implementation-report.md` ## Implementation Summary - Expanded `Workload` to `intune`, `entra`, `exchange`, `teams`, `security_compliance`, `defender`, `purview`, `tenantpilot`, and `unknown`. - Added a reversible migration to update the PostgreSQL workload check constraint, seed 24 representative M365 registry rows, and seed 7 inactive planning scopes. - Added 24 active registry-only resource type definitions: - Entra: `conditionalAccessPolicy`, `securityDefaults`, `application`, `servicePrincipal`, `roleDefinition`, `administrativeUnit` - Exchange: `transportRule`, `acceptedDomain`, `sharedMailbox`, `remoteDomain`, `mailboxPlan`, `organizationConfig` - Teams: `appPermissionPolicy`, `appSetupPolicy`, `meetingPolicy`, `messagingPolicy`, `teamsUpdateManagementPolicy`, `voiceRoute` - Security and Compliance: `labelPolicy`, `retentionCompliancePolicy`, `dlpCompliancePolicy`, `autoSensitivityLabelPolicy`, `protectionAlert`, `complianceTag` - Represented Defender and Purview only in aggregate planning metadata, not as fake certified resource types. - Kept `ResourceTypeRegistry::defaultCanonicalTypes()` Intune-only so default capture paths do not silently expand to M365. - Added Claim Guard statement checks that block broad M365, certified, restore-ready, complete-tenant, all-resource, and unscoped percent claims. Follow-up hardening made this token-based rather than dependent on one wording/order, so variants such as `M365 certified coverage`, `Microsoft 365 certified coverage`, and `M365 restore-ready coverage` are blocked. ## Registry Defaults - New non-Intune rows use `source_class = tcm`. - New non-Intune rows use `support_state = out_of_scope`. - New non-Intune rows use `default_coverage_level = detected`. - New non-Intune rows use `default_evidence_state = not_captured`. - New non-Intune rows use `default_identity_state = derived`. - New non-Intune rows use `default_claim_state = internal_only`. - New non-Intune rows set `allows_beta_claims`, `allows_graph_fallback_claims`, and `allows_certified_claims` to false. - Restore posture is conservative: high-risk entries are `not_restorable`; remaining representative entries are `preview_only`; none are `restorable`. - Catalog metadata uses existing JSONB `metadata`: `documentation_status`, `catalog_source`, `catalog_last_reviewed_at`, `source_aliases`, `risk_tier`, `default_restore_posture`, `is_full_catalog`, `catalog_import_batch`, and `customer_claims_allowed`. - Full-vs-partial decision: all new M365 catalog rows/scopes are partial representative planning truth with `is_full_catalog = false`. ## Supported Scopes Added inactive planning scopes: - `m365_tcm_registry_detected` - `entra_tcm_registry_detected` - `exchange_tcm_registry_detected` - `teams_tcm_registry_detected` - `security_compliance_tcm_registry_detected` - `m365_tcm_generic_future` - `m365_tcm_certified_none` All new M365 scopes use `minimum_coverage_level = detected`, `customer_claims_allowed = false`, `is_active = false`, and registry-only metadata. Existing active Intune scopes remain the only active supported scopes, preserving the Coverage v2 operator surface default scope. ## Guard Proof - No runtime capture path added: no Graph client, provider gateway, HTTP remote call, capture job, scheduler sync, or runtime Microsoft documentation fetch was introduced. - No concrete resource data added by registry sync: `TenantConfigurationResource` and `TenantConfigurationResourceEvidence` remain untouched by defaults/sync. - No `tenant_id` ownership truth added to registry definition tables or Spec 419 changed files. - No workload mini-platform added: no Entra/Exchange/Teams/SecurityCompliance/Defender/Purview tables, models, engines, or namespaces. - No v1 compatibility path added: no v1 adapter, fallback reader, dual write, or old gap taxonomy. - No broad M365 claim is allowed. Internal registry-scoped denominator wording returns `internal_only` only when explicitly requested for operator/internal context. - Rollback guard proof: rollback now deletes only rows tagged with the exact Spec 419 `catalog_import_batch`; if a later migration promotes a Non-Intune row/scope by changing that metadata, rollback preserves it and keeps the PostgreSQL workload check compatible with remaining workloads. ## Product Surface Close-Out - No runtime UI route, Filament page/provider, navigation entry, Blade view, Livewire component, action, report, download, customer output, asset, or rendered label was edited. - Product Surface Impact: existing Spec 418 Coverage v2 operator surface has data-driven impact because active registry rows now render. - UI Surface Impact: existing Coverage v2 resource type registry table can show new M365 rows; no new controls or routes. - Page archetype: internal/operator registry/readiness surface. - Surface budget: existing table/filter/inspect affordances only. - Technical Annex/deep-link demotion: catalog/source details remain internal registry metadata, not customer proof. - Canonical status vocabulary: existing Coverage v2 enum vocabulary only; no legacy gap vocabulary. - Product Surface exceptions: none. - Focused browser proof: PASS via `tests/Browser/Spec419M365RegistryOperatorSurfaceSmokeTest.php`. - Human Product Sanity: PASS. Browser proof showed registry rows with conservative labels (`Out of scope`, `Detected`, `Not included`, `Internal only`), no broad M365 coverage/certification/restore-ready labels, no table capture/restore/certify/publish/export/download/report actions, inactive M365 planning scope keys not rendered, Livewire present, no console or JavaScript errors, and no remote Graph/TCM/provider resource loads. - Visible complexity outcome: broader registry data on the existing surface; no new page family. ## Filament / Livewire / Assets - Livewire v4.0+ compliance: unchanged; no Livewire code was edited. - Provider registration location: unchanged; Laravel panel providers remain registered through `apps/platform/bootstrap/providers.php`. - Global search: no Filament Resource changes; no globally searchable resource added or changed. - Destructive/high-impact actions: none added. - Asset strategy: no new global or on-demand assets; no `filament:assets` deployment requirement introduced. - Testing plan: unit, feature/static, pgsql constraint proof, and focused browser smoke were run. ## Deployment Impact - Migration impact: yes. `2026_06_26_000419_expand_tenant_configuration_workloads.php` updates the PostgreSQL workload check constraint and upserts registry/scope rows. - Rollback impact: deletes only exact Spec 419 planning scopes and M365 registry rows identified by the Spec 419 import-batch metadata. It restores the Intune-only workload check when no later Non-Intune rows remain; if later Non-Intune rows remain, it preserves those rows and constrains to the remaining workload values instead of damaging future entries. - Environment variables: none. - Queues/workers/scheduler: none. - Storage/volumes: none. - Assets: none. - Staging expectation: run migrations and the focused registry/pgsql/browser validation before production promotion. ## Validation - `cd apps/platform && ./vendor/bin/sail php -l app/Services/TenantConfiguration/ResourceTypeRegistry.php`: PASS - `cd apps/platform && ./vendor/bin/sail php -l app/Services/TenantConfiguration/SupportedScopeResolver.php`: PASS - `cd apps/platform && ./vendor/bin/sail php -l app/Services/TenantConfiguration/ClaimGuard.php`: PASS - `cd apps/platform && ./vendor/bin/sail php -l database/migrations/2026_06_26_000419_expand_tenant_configuration_workloads.php`: PASS - `cd apps/platform && ./vendor/bin/sail artisan test tests/Unit/Support/TenantConfiguration tests/Feature/TenantConfiguration`: PASS, 102 passed, 9 skipped - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml tests/Feature/TenantConfiguration/Spec419M365RegistryExpansionTest.php`: PASS, 7 passed - `cd apps/platform && ./vendor/bin/sail artisan test tests/Browser/Spec419M365RegistryOperatorSurfaceSmokeTest.php`: PASS, 1 passed, 28 assertions - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`: PASS - `git diff --check`: PASS ## Deferred Work - Actual M365 capture, compare, render, restore, certification, customer reports, dashboards, and customer-facing M365 claims remain deferred to future specs. - Defender and Purview remain workload-status metadata only until a later spec defines representative resource types with reviewed source truth.