18 KiB
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:
BaselineProfileResourceis 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:assetsremains 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
BaselineScopeintegration 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
SubjectClassandResolutionPathenums. - Map current Intune policy types to
domain_key = intuneandsubject_class = policy, and map current baseline foundations todomain_key = platform_foundationandsubject_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 rolloutdata-model.md: canonical V2 scope document, taxonomy entry model, legacy-ingestion contract, and effective-scope projectioncontracts/governance-subject-taxonomy.logical.openapi.yaml: internal logical contract for registry listing, scope normalization, save-forward writes, and normalized operation startsquickstart.md: implementation and verification sequence for the feature
Design decisions:
- Keep the canonical persisted shape explicit:
version = 2plusentries[]. - Make legacy
policy_typesandfoundation_typesingestion-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)
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)
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
BaselineScopeentrypoint 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.contextand 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
BaselineScopeTestto 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
BaselineCaptureTestandBaselineComparePreconditionsTestto 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.