## Summary - normalize provider-neutral target-scope and identity contracts across provider connection resolution, operation-start gating, verification reporting, and boundary configuration - align provider connection resource, onboarding, tenant summaries, and operation follow-up on the same shared scope contract while keeping Microsoft-specific profile details in provider-owned metadata - add Spec 281 artifacts and focused feature/browser coverage for the new provider-scope contract - move the tenant dashboard context-chip rail into Filament header widgets so the metadata row renders directly under the page subtitle ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Providers/ProviderConnectionTargetScopeNeutralityTest.php tests/Feature/Providers/ProviderIdentityResolutionNeutralityTest.php tests/Feature/Providers/ProviderOperationStartGateTargetScopeContextTest.php tests/Feature/Filament/ProviderConnectionResourceScopeSummaryTest.php tests/Feature/Onboarding/ManagedTenantOnboardingProviderConnectionScopeTest.php tests/Feature/Guards/ProviderConnectionMicrosoftScopeLeakGuardTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Dashboard/TenantDashboardProductizationSummaryTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Dashboard/TenantDashboardProductizationSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` ## Notes - Filament remains on v5 with Livewire v4-compatible surfaces only. - Provider registration location is unchanged; Laravel 11+ providers stay in `apps/platform/bootstrap/providers.php`. - `ProviderConnectionResource` remains non-globally-searchable and still exposes View/Edit pages. - No new asset registration was added; deploy-time `filament:assets` expectations are unchanged. - No new destructive action path was introduced; existing server authorization and confirmation handling remain in place where applicable. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #339
11 KiB
Research: Provider Connection Scope & Microsoft Profile Extraction
Date: 2026-05-07
Branch: 281-provider-connection-scope
Decision 1: Keep 281 as a contract-extraction slice, not a new provider framework
- Decision: limit the slice to provider-neutral target-scope and identity contract extraction across the existing
ProviderConnection, resolver, summary, onboarding, and start-gate seams. - Rationale: current repo truth already contains the right seam inventory:
ProviderConnectionTargetScopeDescriptor,ProviderConnectionTargetScopeNormalizer,ProviderConnectionSurfaceSummary,ProviderIdentityResolution, andProviderOperationStartGate. The problem is the Microsoft-shaped payload still flowing through them, not the absence of a framework. - Alternatives considered:
- Introduce a provider registry or capability framework: rejected because the feature has only one current provider and the constitution explicitly prefers bounded extraction over speculative multi-provider machinery.
- Add a generic provider profile subsystem first: rejected because the current release does not need new persistence to describe provider profile detail.
Decision 2: Treat ProviderConnection as the unchanged persisted source of truth
-
Decision:
ProviderConnectionstays the only persisted binding record for this slice, anchored byworkspace_idplusmanaged_environment_id. Notenant_idmigration work and no provider-profile table are added. -
Rationale:
ProviderConnectionalready belongs toManagedEnvironmentviamanaged_environment_id, and the raw candidate wording about replacingtenant_idis stale. The remaining defect is contract shaping, not relationship ownership. -
Alternatives considered:
- Re-open the old
tenant_idtomanaged_environment_idcandidate: rejected because repo truth already completed that move. - Add a separate provider-profile entity: rejected because provider profile detail is still derived from the current connection and identity-resolution path.
- Re-open the old
-
Documented candidate deviation: the raw candidate also proposed a new shared field family around
provider_key,external_account_id,provider_metadata, and explicit run-context workspace/environment keys. In current repo truth,provider,workspace_id, andmanaged_environment_idalready exist, so this package narrows the shared contract totarget_scope,effective_client_identity, nestedprovider_context, and existing provider-owned metadata instead of inventing new top-level persisted fields.
Decision 3: Make ProviderConnectionTargetScopeDescriptor the canonical shared target_scope contract
- Decision: standardize every shared target-scope output on
provider,scope_kind,scope_identifier,scope_display_name,shared_label, andshared_help_textinstead of any Microsoft-named top-level keys. - Rationale: the descriptor already exists and already exposes the right field names. What is missing is consistent reuse across resolver, audit, UI summary, onboarding, and run-context seams.
- Alternatives considered:
- Keep
target_scope.entra_tenant_idalongside the neutral fields: rejected because pre-production lean doctrine favors canonical replacement over shared compatibility aliases. - Add a second DTO or presenter for neutral naming: rejected because the existing descriptor already covers the need.
- Keep
Decision 4: Reshape the shared identity result around effective client identity and nested provider context
- Decision: keep
ProviderIdentityResolutionas the single shared identity-result object, but move its planned contract center of gravity totarget_scope,effective_client_identity,blocked_reason, and nestedprovider_contextrather than sharedtenantContextnaming. - Rationale: the current implementation already carries these concepts as
targetScope,effectiveClientId,credentialSource, and contextual detail arrays. The shared leak is thetenantContextfield name and its downstream use as the primary field in platform-core seams, so the package standardizes the planned artifact language ontarget_scope,effective_client_identity, andprovider_context. - Alternatives considered:
- Leave
tenantContextas the canonical shared field and just add neutral labels in UI: rejected because the identity contract would remain Microsoft-shaped below the UI. - Split dedicated and platform identities into new separate result types: rejected because one existing result object already supports both paths.
- Leave
Decision 5: Keep Microsoft-specific detail inside provider-owned profile or context metadata
- Decision: preserve Microsoft tenant ID, authority tenant, redirect URI, consent URL shaping, and Graph runtime options only inside provider-owned nested metadata or provider-owned consumer seams such as
ProviderIdentityContextMetadata,AdminConsentUrlFactory, andProviderGateway. - Rationale: the boundary catalog already marks identity resolution and operation start as platform-core while runtime transport and consent URL shaping remain provider-owned. The narrowest fix is to push Microsoft semantics outward, not to pretend they disappear.
- Alternatives considered:
- Strip Microsoft detail from all outputs entirely: rejected because support, consent, and troubleshooting still need those fields.
- Keep Microsoft detail as top-level fields in shared summaries: rejected because that keeps the platform-core contract Microsoft-shaped.
Decision 6: Reuse ProviderConnectionSurfaceSummary as the only summary adapter
- Decision: keep
ProviderConnectionSurfaceSummaryas the one summary contract reused byProviderConnectionResource,ManagedTenantOnboardingWizard, and managed-environment related-context summaries. - Rationale: the wizard already calls
ProviderConnectionSurfaceSummary::forConnection($connection)->targetScopeSummary(), and the resource already delegates summary rendering there. Reusing the same adapter is the narrowest way to remove duplicate truth. - Alternatives considered:
- Let onboarding and provider-connections each compute their own neutral labels: rejected because it would create the second identity story this feature is meant to remove.
- Put raw
entra_tenant_idback into onboarding for clarity: rejected because it would reintroduce a Microsoft-only summary path.
Decision 7: Rewrite provider-operation start context to use neutral shared scope fields
- Decision:
ProviderOperationStartGateshould emit the neutraltarget_scopedescriptor in started and blocked run context, with any Microsoft-specific detail nested under provider-owned provider-context metadata. - Rationale: the start gate is one of the explicit boundary hotspots in
config/provider_boundaries.php, and it still writestarget_scope.entra_tenant_iddirectly today. Later artifact and taxonomy work would inherit that leak if it stays. - Alternatives considered:
- Leave the start-gate context alone and only update UI summaries: rejected because
OperationRuncontext is shared operational truth. - Add neutral fields beside
entra_tenant_id: rejected because the feature is pre-production and should replace the shared shape rather than dual-write it.
- Leave the start-gate context alone and only update UI summaries: rejected because
Decision 8: Keep credential validation neutral at the platform-core seam
- Decision:
CredentialManagerstays the existing credential access seam, but its scope-validation rule and error wording should align to the normalized target-scope identifier rather than a Microsoft-shaped mismatch message. - Rationale:
CredentialManageris already inside the shared provider identity path and currently compares a payload scope assertion againstconnection->entra_tenant_id. That is acceptable as an implementation detail, but not as the platform-core contract wording. - Alternatives considered:
- Ignore the message mismatch and leave it Microsoft-shaped: rejected because it leaks provider semantics back into the shared identity failure path.
- Change provider-credential persistence shape now: rejected because no new persistence is justified for this slice.
Decision 9: Keep Filament surface behavior and deployment strategy unchanged
- Decision:
ProviderConnectionResourceremains non-globally-searchable, keepsViewandEditpages, preserves the current confirmation-protected mutations, and adds no new asset registration. - Rationale: the feature changes summary and contract shaping only. The current resource already satisfies the required Filament action and search guardrails.
- Alternatives considered:
- Enable global search for provider connections while touching the resource: rejected because the feature does not need it and the spec explicitly keeps it out of scope.
- Add new UI chrome or asset bundles for provider profile detail: rejected because the existing resource and wizard can carry the nested disclosure.
Decision 10: Prove the slice with focused feature coverage and one browser smoke
- Decision: use focused provider feature tests, one Filament/browser smoke covering provider-connections plus onboarding, and keep proof commands identical across spec, plan, and quickstart.
- Rationale: this slice changes shared contract truth across several PHP seams and two operator-facing consumers, but it does not justify a new heavy-governance family or broad browser matrix.
- Alternatives considered:
- Feature tests only: rejected because the live resource plus onboarding continuity is part of the user-visible contract.
- Broad browser or smoke expansion across unrelated provider pages: rejected because it would create unnecessary suite cost.
Final Research Outcome
ProviderConnectionandProviderCredentialpersistence stay unchanged.- The canonical shared
target_scopecontract is the existing descriptor shape, notentra_tenant_id. - The canonical shared identity result is the existing
ProviderIdentityResolutionseam, but its planned contract must stop centeringtenantContextas shared truth and instead standardize ontarget_scope,effective_client_identity, and nestedprovider_context. - Provider-specific Microsoft details remain available through
ProviderIdentityContextMetadataand provider-owned consumers only. ProviderConnectionSurfaceSummarystays the one summary adapter for provider-connections, onboarding, and related context.ProviderOperationStartGatebecomes the critical contract rewrite point for neutral run context.ProviderConnectionResourceremains non-globally-searchable with confirmation-protected mutations intact.- The narrowest honest proof is the feature suite already named in the spec, one browser smoke, and no new runtime abstractions.