# Implementation Plan: Governance Subject Taxonomy and Baseline Scope V2 **Branch**: `202-governance-subject-taxonomy` | **Date**: 2026-04-13 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/202-governance-subject-taxonomy/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/202-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, route baseline capture and compare through normalized effective scope with explicit eligibility validation and auditable operation context, and keep any optional cleanup path preview-first and auditable for baseline profile rows only. 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/202-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 preview-first maintenance command with explicit write confirmation and audit logging, 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/202-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 that defaults to preview mode, requires explicit write confirmation, and writes audit entries for committed rewrites. ## Project Structure ### Documentation (this feature) ```text specs/202-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 that previews remaining legacy baseline profile scope rows by default and backfills them to canonical V2 only after explicit write confirmation, with audit logging for committed rewrites. - Keep `baseline_tenant_assignments.override_scope_jsonb` on tolerant-read normalization only in this release. - 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, including preview mode, explicit write confirmation, audit logging, and 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.