# Implementation Plan: Governance Subject Taxonomy and Baseline Scope V2 **Branch**: `001-governance-subject-taxonomy` | **Date**: 2026-04-13 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/001-governance-subject-taxonomy/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/001-governance-subject-taxonomy/spec.md` **Note**: This plan upgrades baseline scope semantics from legacy Intune-shaped lists to a versioned governance-subject contract while preserving current Intune baseline behavior and keeping rollout risk low. ## Summary Introduce a platform-safe governance subject taxonomy registry and a canonical Baseline Scope V2 document for existing baseline profiles. Reuse current config catalogs and support metadata as registry contributors, evolve the existing `BaselineScope` integration point into a V2-aware normalizer, persist canonical V2 on save, keep the current Intune-first baseline UI understandable, and route baseline capture and compare through normalized effective scope with explicit eligibility validation and auditable operation context. No new table, no new `OperationRun` type, and no broad `policy_type` rename are required. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, Pest v4, Tailwind CSS v4, Laravel Sail, existing `BaselineScope`, `InventoryPolicyTypeMeta`, `BaselineSupportCapabilityGuard`, `BaselineCaptureService`, and `BaselineCompareService` **Storage**: PostgreSQL via existing `baseline_profiles.scope_jsonb`, `baseline_tenant_assignments.override_scope_jsonb`, and `operation_runs.context`; no new tables planned **Testing**: Pest unit, feature, and focused Filament Livewire tests run through Laravel Sail **Target Platform**: Laravel monolith web application under `apps/platform` **Project Type**: web application **Performance Goals**: Keep taxonomy lookup and scope normalization fully in-process, avoid new remote calls or query fan-out on baseline surfaces, and keep capture or compare start overhead effectively unchanged aside from deterministic validation **Constraints**: No eager migration, no new `OperationRun` type, no broad repo-wide `policy_type` rename, no generic plugin system, no UI overclaim of inactive domains, and no new panel/provider or asset work **Scale/Scope**: One workspace-owned baseline resource, one model-cast integration point, two baseline start services, one config-backed taxonomy contributor set, one optional maintenance command, and focused unit/feature/Filament regression coverage ## Constitution Check *GATE: Passed before Phase 0 research. Re-checked after Phase 1 design and still passing.* | Principle | Pre-Research | Post-Design | Notes | |-----------|--------------|-------------|-------| | Inventory-first / snapshots-second | PASS | PASS | The feature changes baseline definition semantics only; inventory and snapshot truth sources remain unchanged. | | Read/write separation | PASS | PASS | Save-forward writes stay on existing baseline profile save flows and retain current audit behavior; capture and compare still run through existing operation starts. | | Graph contract path | N/A | N/A | No new Microsoft Graph path or contract-registry change is introduced. | | Deterministic capabilities | PASS | PASS | The new taxonomy registry reuses existing config plus `InventoryPolicyTypeMeta::baselineSupportContract()` and remains snapshot-testable. | | Workspace + tenant isolation | PASS | PASS | Baseline profiles remain workspace-owned; tenant compare and capture operations remain tenant-scoped and unchanged in authorization boundaries. | | RBAC-UX authorization semantics | PASS | PASS | No new authorization plane or capability path is introduced; non-members remain `404` and in-scope capability failures remain `403`. | | Run observability / Ops-UX | PASS | PASS | Existing `baseline_capture` and `baseline_compare` runs are reused; only the effective scope payload becomes canonical and more explicit. | | Data minimization | PASS | PASS | No new persistence or secret-bearing payloads are introduced; scope remains derived from existing config and baseline data. | | Proportionality / anti-bloat | PASS | PASS | The registry and V2 scope are justified by a current contract problem and two existing concrete catalogs; no universal plugin framework is added. | | No premature abstraction | PASS | PASS | The registry consolidates existing supported policy types and foundation types into one authoritative contract instead of adding a speculative extension system. | | Persisted truth / behavioral state | PASS | PASS | V2 stays inside existing `scope_jsonb`; no new table or independent lifecycle is added. | | UI semantics / few layers | PASS | PASS | Operator summaries derive directly from canonical scope; no presenter or explanation framework is introduced. | | Filament v5 / Livewire v4 compliance | PASS | PASS | The plan stays inside existing Filament resources and Livewire-backed pages. | | Provider registration location | PASS | PASS | No panel or provider change is required; Laravel 11+ provider registration remains in `bootstrap/providers.php`. | | Global search hard rule | PASS | PASS | `BaselineProfileResource` already disables global search and this plan does not change that. | | Destructive action safety | PASS | PASS | No new destructive action is introduced. Existing destructive actions on baseline surfaces must keep confirmation and authorization unchanged. | | Asset strategy | PASS | PASS | No new assets are required. Existing deployment handling of `cd apps/platform && php artisan filament:assets` remains unchanged. | ## Filament-Specific Compliance Notes - **Livewire v4.0+ compliance**: The affected baseline surfaces remain on Filament v5 + Livewire v4 and no legacy API is introduced. - **Provider registration location**: No new panel or provider is needed; Laravel 11+ provider registration remains in `bootstrap/providers.php`. - **Global search**: `BaselineProfileResource` is already not globally searchable, so the hard rule about view or edit pages is unaffected. - **Destructive actions**: This feature adds no new destructive action. Existing destructive actions on baseline surfaces must retain `->requiresConfirmation()` and server-side authorization. - **Asset strategy**: No global or on-demand asset registration is planned. Deployment handling of `cd apps/platform && php artisan filament:assets` remains unchanged. - **Testing plan**: Extend unit coverage for scope normalization and taxonomy lookups, extend baseline capture and compare feature coverage for normalized effective scope and support gating, extend Filament baseline profile tests for save-forward behavior and UI honesty, and add focused coverage for the optional backfill command. ## Phase 0 Research Research outcomes are captured in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/001-governance-subject-taxonomy/research.md`. Key decisions: - Evolve the existing `BaselineScope` integration point into the V2-aware orchestration layer instead of adding a parallel top-level scope class. - Build the governance taxonomy registry by composing current `tenantpilot.supported_policy_types`, `tenantpilot.foundation_types`, and existing baseline support metadata rather than introducing a second config truth source. - Introduce platform-facing governance domain and subject-class vocabulary separate from the existing baseline support `SubjectClass` and `ResolutionPath` enums. - Map current Intune policy types to `domain_key = intune` and `subject_class = policy`, and map current baseline foundations to `domain_key = platform_foundation` and `subject_class = configuration_resource`. - Use tolerant read plus save-forward for rollout and keep backfill as an optional maintenance command, not a migration. - Keep operator selection Intune-first for now and derive canonical V2 internally rather than expanding the UI into a fake multi-domain selector. - Record canonical effective scope in operation context while keeping temporary compatibility projections only where existing consumers still require them. - Merge duplicate entries deterministically when domain, subject class, and filters match, and reject ambiguous overlaps when they do not. ## Phase 1 Design Design artifacts are created under `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/001-governance-subject-taxonomy/`: - `research.md`: decisions and rejected alternatives for taxonomy, scope, and rollout - `data-model.md`: canonical V2 scope document, taxonomy entry model, legacy-ingestion contract, and effective-scope projection - `contracts/governance-subject-taxonomy.logical.openapi.yaml`: internal logical contract for registry listing, scope normalization, save-forward writes, and normalized operation starts - `quickstart.md`: implementation and verification sequence for the feature Design decisions: - Keep the canonical persisted shape explicit: `version = 2` plus `entries[]`. - Make legacy `policy_types` and `foundation_types` ingestion-only and normalize them immediately. - Keep current Filament baseline profile forms Intune-first while rendering normalized scope summaries from canonical V2. - Reuse existing baseline support capability checks by attaching them to registry entries instead of duplicating support logic in the scope model. - Store canonical effective scope in operation context for capture and compare so audit and debugging no longer depend on reconstructing legacy lists. - Keep the optional cleanup path outside normal request flows and implement it as a one-time maintenance command. ## Project Structure ### Documentation (this feature) ```text specs/001-governance-subject-taxonomy/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── spec.md ├── contracts/ │ └── governance-subject-taxonomy.logical.openapi.yaml └── checklists/ └── requirements.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Console/Commands/ │ │ └── [optional legacy-scope backfill command] │ ├── Filament/ │ │ └── Resources/ │ │ ├── BaselineProfileResource.php │ │ └── BaselineProfileResource/ │ │ └── Pages/ │ │ ├── CreateBaselineProfile.php │ │ ├── EditBaselineProfile.php │ │ └── ViewBaselineProfile.php │ ├── Models/ │ │ └── BaselineProfile.php │ ├── Services/ │ │ └── Baselines/ │ │ ├── BaselineCaptureService.php │ │ └── BaselineCompareService.php │ └── Support/ │ ├── Baselines/ │ │ ├── BaselineScope.php │ │ ├── BaselineSupportCapabilityGuard.php │ │ ├── ResolutionPath.php │ │ └── SubjectClass.php │ ├── Governance/ │ │ └── [new taxonomy records and registry] │ └── Inventory/ │ └── InventoryPolicyTypeMeta.php ├── config/ │ └── tenantpilot.php └── tests/ ├── Feature/ │ ├── Baselines/ │ │ ├── BaselineCaptureTest.php │ │ ├── BaselineComparePreconditionsTest.php │ │ ├── BaselineSupportCapabilityGuardTest.php │ │ └── [new scope-v2 and backfill coverage] │ └── Filament/ │ ├── BaselineProfileFoundationScopeTest.php │ ├── BaselineProfileCaptureStartSurfaceTest.php │ └── BaselineProfileCompareStartSurfaceTest.php └── Unit/ └── Baselines/ ├── BaselineScopeTest.php └── [new taxonomy registry coverage] ``` **Structure Decision**: Keep the work inside the existing baseline model, baseline services, and Filament resource surfaces. Add one narrow `Support/Governance` namespace for platform-facing taxonomy records and registry logic, but do not introduce a wider plugin or extension framework. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | Governance taxonomy registry | The product already has two concrete baseline subject catalogs and one support-metadata contract that need a single authoritative selection view now | Leaving config arrays and support logic separate would preserve the hidden semantic split that this spec is explicitly fixing | | Baseline Scope V2 document and entry model | Legacy dual-list scope cannot express domain, subject class, or future-safe filters and cannot support a stable compare-input contract | Extending `policy_types` and `foundation_types` with ad-hoc flags would keep the model Intune-shaped and ambiguous | ## Proportionality Review - **Current operator problem**: Baseline scope still hides governed-subject meaning behind Intune policy lists and an unnamed foundation list, which makes validation, auditability, and compare-input semantics harder than they should be. - **Existing structure is insufficient because**: Legacy scope cannot express domain ownership or platform-level subject shape, and the current support metadata lives separately from the selection contract. - **Narrowest correct implementation**: Reuse existing config and support contributors, introduce a small taxonomy registry plus V2 scope document, normalize legacy payloads deterministically, and keep UI and run semantics otherwise unchanged. - **Ownership cost created**: One new support namespace, explicit mapping maintenance for taxonomy entries, additional normalization and no-regression tests, and one optional backfill command to maintain. - **Alternative intentionally rejected**: A local wrapper around legacy arrays or a broad rename/plugin system were rejected because the former keeps the semantic leak and the latter imports unnecessary churn and abstraction. - **Release truth**: current-release contract correction that deliberately prepares the input boundary needed for Spec 203 ## Implementation Strategy ### Phase A — Taxonomy Registry and Platform Vocabulary - Add platform-facing governance domain and subject-class enums or records. - Implement a taxonomy registry that composes current supported policy types, foundation types, labels, descriptions, and support flags. - Keep existing support-resolution enums (`SubjectClass`, `ResolutionPath`) as internal capability metadata rather than reusing them as the operator-facing taxonomy. ### Phase B — Canonical Scope V2 and Legacy Normalization - Upgrade the current `BaselineScope` entrypoint to accept legacy and V2 payloads. - Add canonical V2 entries, deterministic duplicate handling, and strict mixed-payload rejection. - Preserve derived compatibility helpers only where current UI or tests still require them during rollout. ### Phase C — Save-Forward Persistence and UI Integration - Update baseline profile persistence so new and saved profiles write canonical V2 into `scope_jsonb`. - Keep current Intune-first selectors for now, but derive canonical entries from them on save. - Add normalized scope summaries to touched baseline surfaces without exposing raw V2 JSON. ### Phase D — Capture/Compare Integration and Auditable Scope Context - Route baseline capture and compare through normalized effective scope. - Apply eligibility gating before enqueue when selected subject types are unsupported for the requested operation. - Write canonical effective scope into `OperationRun.context` and retain transitional projections only where existing consumers still need them. ### Phase E — Optional Cleanup and Verification - Add an optional Artisan maintenance command to backfill remaining legacy scope rows to canonical V2. - Extend unit, feature, and Filament test suites for normalization, save-forward behavior, operation gating, UI honesty, and no-regression baseline flows. - Keep current audit, authorization, and run-observability behavior green throughout the rollout. ## Risk Assessment | Risk | Impact | Likelihood | Mitigation | |------|--------|------------|------------| | The registry becomes a second or speculative truth source | High | Medium | Build it from existing config and support metadata contributors rather than from new hand-maintained arrays. | | Foundation mapping chooses the wrong domain or subject-class shape | Medium | Medium | Keep the mapping explicit, minimal, and covered by registry tests so it can evolve intentionally in later specs rather than implicitly. | | Legacy and V2 payloads silently diverge during transition | High | Medium | Reject mixed payloads, normalize deterministically, and add save-forward plus backfill coverage. | | Capture or compare still bypasses canonical scope in one code path | High | Medium | Centralize effective-scope derivation through the upgraded scope contract and add feature tests on both start services. | | UI starts implying future domain readiness too early | Medium | Low | Only expose active and supported subject types and keep the current selector intentionally Intune-first. | ## Test Strategy - Extend `BaselineScopeTest` to cover legacy normalization into V2, duplicate merge or rejection rules, mixed-payload rejection, and explicit V2 serialization. - Add focused registry coverage for domain, subject-class, subject-type, and support-flag mapping from the current config contributors. - Extend `BaselineCaptureTest` and `BaselineComparePreconditionsTest` to assert canonical effective scope and operation-support gating before run creation. - Add focused feature coverage for the optional backfill command and for legacy rows becoming canonical V2 on save. - Extend Filament baseline profile tests to verify Intune-first form behavior still works, canonical V2 is persisted, and normalized scope summaries remain operator-safe. - Keep existing baseline authorization and start-surface tests green so save-forward semantics do not weaken access control or operator-flow clarity.