# Implementation Plan: Spec 421 - Entra Core Comparable / Renderable Pack **Branch**: `421-entra-core-comparable-renderable-pack` | **Date**: 2026-06-27 | **Spec**: `specs/421-entra-core-comparable-renderable-pack/spec.md` **Input**: Feature specification from `/specs/421-entra-core-comparable-renderable-pack/spec.md` ## Summary Promote selected Entra Coverage v2 evidence to comparable/renderable support without adding capture scope, restore, certification, customer output, or an Entra mini-platform. The mandatory implementation-ready slice is `conditionalAccessPolicy` because current repo truth already has a content-backed source contract path from Spec 420. `securityDefaults`, `application`, `servicePrincipal`, `roleDefinition`, and `administrativeUnit` remain evidence-gated and may be promoted only when preflight proves repo-real content-backed evidence already exists. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 **Primary Dependencies**: Existing Tenant Configuration / Coverage v2 services, `GraphClientInterface` only for existing evidence capture paths, `ClaimGuard`, `BadgeCatalog`/`BadgeRenderer`, Pest 4 **Storage**: Existing PostgreSQL tables for `tenant_configuration_resource_types`, `tenant_configuration_resources`, and `tenant_configuration_resource_evidence`; no new table by default **Testing**: Pest 4 unit, feature, and focused browser if rendered UI changes **Validation Lanes**: fast-feedback, confidence, browser if rendered output changes **Target Platform**: Laravel Sail locally, Dokploy container deployment for staging/production **Project Type**: web app under `apps/platform` **Performance Goals**: render/compare from persisted evidence only; no remote/provider calls during UI render **Constraints**: no restore, no certification, no customer-facing claims, no new capture contract, no `tenant_id`, no Entra mini-platform, no new OperationRun type **Scale/Scope**: one mandatory evidence-backed resource type (`conditionalAccessPolicy`), optional Entra types only if already content-backed and testable ## UI / Surface Guardrail Plan - **Guardrail scope**: existing internal/operator Coverage v2 surface may change through rendered evidence/status summaries. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: existing `CoverageV2Readiness` page, `CoverageV2ResourceTypesTable`, `CoverageV2ResourceInstancesTable`, inspect slide-over, and read model if rendered summaries are exposed. No new route, navigation, panel provider, action, report, download, or customer surface. - **No-impact class, if applicable**: N/A - rendered data may change. - **Native vs custom classification summary**: native Filament + existing widgets/read model. - **Shared-family relevance**: evidence/status/read-only registry and inspect details. - **State layers in scope**: page/detail evidence display; no shell/navigation state. - **Audience modes in scope**: operator-MSP and support-platform; no customer/read-only output. - **Decision/diagnostic/raw hierarchy plan**: typed summary first, diagnostics second, raw/support evidence hidden or secondary. - **Raw/support gating plan**: raw payload not default-visible; secrets never shown. - **One-primary-action / duplicate-truth control**: keep existing inspect link as the only action; no capture/restore/certify/export action. - **Handling modes by drift class or surface**: Product Surface and browser proof are review-mandatory if rendered output changes; runtime UI expansion is hard-stop until spec/plan/tasks are amended. - **Repository-signal treatment**: report-only for no new UI files; review-mandatory for existing rendered output changes; exception-required for any new surface/action. - **Special surface test profiles**: shared-detail-family / standard-native-filament. - **Required tests or manual smoke**: focused browser if rendered output changes; feature tests for no raw/default overclaim. - **Exception path and spread control**: none. - **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage. - **UI/Productization coverage decision**: existing internal surface only; no coverage artifact unless UI scope expands. - **Coverage artifacts to update**: none by default. - **No-impact rationale**: N/A. - **Navigation / Filament provider-panel handling**: no provider/panel/navigation change. - **Screenshot or page-report need**: no page report by default; browser proof is sufficient for existing internal surface rendering. ## Product Surface Contract Plan - **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md`. - **No-legacy posture**: canonical Coverage v2 extension; no compatibility exception. - **Page archetype and surface budget plan**: Existing Technical Annex / internal operator evidence inspection surface; budgets pass because no new page/action family is added. - **Technical Annex and deep-link demotion plan**: OperationRun links, evidence IDs, source keys, raw/normalized payloads, provider IDs, permission context, and unsupported fields remain secondary/diagnostic. - **Canonical status vocabulary plan**: Use existing Coverage v2 labels and canonical status wording; no `Entra covered`, `certified`, `restore-ready`, `customer-ready`, or `100%` labels. - **Product Surface exceptions**: none. - **Browser verification plan**: focused Coverage v2 route/inspect flow if rendered output changes; otherwise `N/A - no rendered UI surface changed` with proof. - **Human Product Sanity plan**: required if rendered output changes; result in implementation report. - **Visible complexity outcome target**: neutral or decreased. - **Implementation report target**: `specs/421-entra-core-comparable-renderable-pack/implementation-report.md`. ## Filament / Livewire / Deployment Posture - **Livewire v4 compliance**: Livewire v4.x confirmed; no Livewire v3 APIs. - **Panel provider registration location**: no panel provider change; Laravel 12 provider registration remains `apps/platform/bootstrap/providers.php`. - **Global search posture**: no Filament Resource global-search behavior changed; no new Resource. - **Destructive/high-impact action posture**: none. No restore/apply/capture/export/certify action is introduced. - **Asset strategy**: no assets by default; `filament:assets` is not newly required beyond existing deployment practice. - **Testing plan**: unit tests for typed behavior; feature tests for evidence-gated promotion, claims, redaction, scope, no overclaim; browser proof if rendered output changes. - **Deployment impact**: no env vars, migrations, queues, scheduler, storage, or assets expected. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: `ResourceTypeRegistry`, `TenantConfigurationResourceType`, `TenantConfigurationResource`, `TenantConfigurationResourceEvidence`, `GenericPayloadNormalizer`, `CoveragePayloadRedactor`, `CoverageIdentityStrategyRegistry`, `CanonicalIdentityResolver`, `ClaimGuard`, `CoverageV2ReadinessReadModel`, existing Coverage v2 widgets if rendered. - **Shared abstractions reused**: Existing Coverage v2 registry, evidence, identity, redaction, Claim Guard, badges, and read-only operator surface. - **New abstraction introduced? why?**: Bounded Entra typed normalizer/comparator/render summary helpers may be introduced because generic payload sorting/redaction is insufficient for operator-safe Conditional Access comparison. - **Why the existing abstraction was sufficient or insufficient**: Existing structures are sufficient for ownership, evidence, identity, claims, redaction, and rendering host; insufficient for typed Entra material-field semantics. - **Bounded deviation / spread control**: Entra-specific field semantics stay inside bounded helpers/config for evidence-backed types and must not become a provider framework. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no new start/completion/link UX. - **Central contract reused**: N/A by default; existing OperationRun links remain diagnostics only if already present. - **Delegated UX behaviors**: N/A. - **Surface-owned behavior kept local**: read-only inspect only. - **Queued DB-notification policy**: N/A. - **Terminal notification path**: N/A. - **Exception path**: none. If compare/render becomes long-running or persisted as an operation, stop and amend the spec. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes. - **Provider-owned seams**: Entra resource names, Graph field names, Conditional Access targeting/control semantics, optional Security Defaults fields. - **Platform-core seams**: Coverage v2 evidence/resource state, coverage level, identity state, claim state, redaction boundary, workspace/managed-environment/provider connection ownership, Product Surface output. - **Neutral platform terms / contracts preserved**: resource type, evidence, compare result, render summary, coverage level, claim state, identity state, provider connection, managed environment. - **Retained provider-specific semantics and why**: Necessary to compare/render actual Entra evidence; bounded to current selected resource types. - **Bounded extraction or follow-up path**: document-in-feature for optional type blockers; follow-up-spec for missing Security Defaults capture/source contract. ## Constitution Check - Inventory/evidence truth: PASS. Render/compare derives from existing last-observed evidence; it does not create customer proof. - Read/write separation: PASS. No provider write, restore, apply, or mutating UI action. - Graph contract path: PASS by default. No new capture or render-time Graph calls; any existing evidence remains from existing contract paths. - Deterministic capabilities: PASS. Coverage-level promotion and compare behavior are testable. - Workspace isolation: PASS with workspace + managed environment + provider connection scope requirements. - RBAC-UX: PASS with existing Evidence View authorization and no action surface. - OperationRun: PASS by default. No new OperationRun type or lifecycle; existing links remain diagnostics only. - Evidence anchor/currentness: PASS if evidence is explicit and no fallback-to-latest is added. - Customer output: PASS. No customer-facing output, report, download, or customer-ready claim. - Provider boundary: PASS if Entra semantics stay in bounded typed helpers and provider-native IDs remain metadata. - Product Surface: PASS with existing-surface proof and Product Surface exceptions `none`. - Test governance: PASS with Unit/Feature/Browser-if-rendered lanes named. - Proportionality: PASS. Typed helpers are justified by operator-safe compare/render and avoid new tables/frameworks. - No premature abstraction: PASS if implementation avoids generic provider frameworks and separate Entra engines. - Persisted truth: PASS by default. Existing evidence remains truth; compare/render derived unless spec amended. - Behavioral state: PASS using existing coverage levels and derived non-persisted importance labels. - No legacy / lean doctrine: PASS. No adapters, dual reads/writes, fallback readers, legacy aliases, or `tenant_id`. ## Testing / Lane / Runtime Impact - **Test purpose / classification by changed surface**: Unit for normalization/compare/render/redaction/Claim Guard; Feature for evidence-gated promotion, RBAC/scope/no-overclaim/no-restore/no-certification/no-tenant-id/no-mini-platform; Browser if rendered Coverage v2 output changes. - **Validation lane(s)**: fast-feedback, confidence, browser-if-rendered. - **Fixture/helper/factory cost**: minimal workspace/managed-environment/provider/evidence setup; fake payloads only; no live Graph/TCM calls. - **Heavy-family visibility**: none expected. - **Reviewer handoff**: confirm optional type blockers are documented, no runtime capture expansion occurred, and no hidden customer output or UI action was introduced. - **Planned validation commands**: - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfiguration/Spec421EntraConditionalAccessNormalizerTest.php tests/Unit/Support/TenantConfiguration/Spec421EntraComparableDiffTest.php tests/Unit/Support/TenantConfiguration/Spec421EntraRenderableSummaryTest.php tests/Unit/Support/TenantConfiguration/Spec421EntraRedactionTest.php tests/Unit/Support/TenantConfiguration/Spec421EntraClaimGuardTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration/Spec421EntraComparableRenderableTest.php tests/Feature/TenantConfiguration/Spec421EntraCoverageLevelPromotionTest.php tests/Feature/TenantConfiguration/Spec421EntraNoRestoreNoCertificationTest.php tests/Feature/TenantConfiguration/Spec421EntraNoTenantIdTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec421EntraComparableRenderableOperatorSurfaceSmokeTest.php` if rendered output changes - `git diff --check` ## Likely Repo Surfaces Runtime implementation should verify current names before editing, but likely surfaces are: - `apps/platform/app/Services/TenantConfiguration/GenericPayloadNormalizer.php` - `apps/platform/app/Services/TenantConfiguration/CoveragePayloadRedactor.php` - `apps/platform/app/Services/TenantConfiguration/ClaimGuard.php` - `apps/platform/app/Services/TenantConfiguration/ResourceTypeRegistry.php` - `apps/platform/app/Services/TenantConfiguration/CoverageV2ReadinessReadModel.php` - `apps/platform/app/Filament/Pages/TenantConfiguration/CoverageV2Readiness.php` - `apps/platform/app/Filament/Widgets/TenantConfiguration/CoverageV2ResourceTypesTable.php` - `apps/platform/app/Filament/Widgets/TenantConfiguration/CoverageV2ResourceInstancesTable.php` - New bounded helper files under `apps/platform/app/Services/TenantConfiguration/` if needed, such as `EntraComparablePayloadNormalizer.php`, `EntraCoverageComparator.php`, and `EntraRenderableSummaryBuilder.php`. - Focused Spec 421 tests under `apps/platform/tests/Unit/Support/TenantConfiguration/`, `apps/platform/tests/Feature/TenantConfiguration/`, and `apps/platform/tests/Browser/` if rendered output changes. ## Domain / Model Implications - No new database table, migration, persisted compare result table, or model is expected. - `TenantConfigurationResourceEvidence.coverage_level` and existing CoverageLevel values can represent `comparable` / `renderable`. - Registry defaults for Entra types must not imply broad support or customer claims. Promotion should be evidence-gated and internal. - Derived compare importance labels must not become a persisted taxonomy. - Raw payload remains an internal evidence storage boundary; render summaries use redacted/normalized data. ## Implementation Phases ### Phase 0 - Preflight And Evidence Matrix Capture branch, HEAD, dirty state, activated skills, related completed-spec guardrail, and stop conditions. Verify current Coverage v2 service names and evidence availability for all draft Entra types. Record which types are content-backed, blocked, or deferred. ### Phase 1 - Tests First: Typed Semantics And Safety Add focused Pest unit tests for Conditional Access normalization, deterministic compare, render summaries, volatile-field handling, redaction, and Claim Guard. Add evidence-gated tests for Security Defaults and optional types so missing evidence remains an explicit blocker. ### Phase 2 - Evidence-Gated Promotion Implement or extend the narrow promotion path so only content-backed, typed-tested resource evidence can report comparable/renderable support. Do not promote any missing-evidence type. ### Phase 3 - Entra Typed Normalization Add bounded typed normalization for Conditional Access and any evidence-backed optional type. Exclude volatile fields, preserve unsupported fields as diagnostics, and keep identity/source metadata separate. ### Phase 4 - Entra Compare Add deterministic compare semantics for selected typed payloads. Classify changes, ignore volatile fields, handle redacted values, use stable ordering, and attach derived bounded importance labels. ### Phase 5 - Entra Render Summaries Add operator-safe render summaries. Conditional Access summary must include state, targets, conditions, grant/session controls, claim/identity state, unsupported/redacted diagnostics, and last captured time without raw payload display. ### Phase 6 - Claim Guard, Product Surface, RBAC, And Evidence Boundaries Extend Claim Guard tests for Entra wording, ensure read model/surface output stays internal and authorized, and confirm no customer output, restore/certification, direct Graph calls, or raw default payload rendering. ### Phase 7 - Browser Proof If Rendered If rendered output changes, add focused browser proof for the existing Coverage v2 surface and inspect slide-over. Verify no console errors, no Livewire/Filament errors, no secrets/raw payload, and no restore/certify/customer-ready claim. ### Phase 8 - Validation And Implementation Report Run focused validation, `git diff --check`, and complete the implementation report with matrices, Product Surface close-out, tests, browser/no-browser, deployment impact, no completed-spec rewrite assertion, and deferred work. ## Stop Conditions - Security Defaults or optional Entra types need new capture/source contracts to become content-backed. - Any implementation proposes restore/apply, certification, customer-facing output, Review Pack/report/PDF output, export/download, or broad coverage claims. - A new OperationRun type, new capture start action, new route/navigation/dashboard, or new persisted compare table is proposed without amending the spec. - Raw payloads, secrets, credentials, tokens, provider response bodies, or provider IDs become default-visible. - `tenant_id` appears as Coverage v2 ownership truth. - A separate Entra table family, engine, dashboard, or provider mini-platform appears. - Render/compare performs Graph/TCM/provider/HTTP work at render time. ## Draft-To-Repo Deviation Handling - The user draft's minimum `securityDefaults` promotion is changed to evidence-gated promotion because current repo truth does not prove content-backed evidence for Security Defaults and the draft forbids faking typed support or adding missing capture. - The user draft's optional initial resource list remains as preflight candidates, not mandatory implementation scope. - The implementation report must include a matrix explaining promoted and deferred types.