# Data Model: Provider Connection Scope & Microsoft Profile Extraction **Date**: 2026-05-07 **Branch**: `281-provider-connection-scope` ## Overview This slice introduces no new persistence. It keeps the existing provider-connection, credential, and run records intact and instead standardizes the derived runtime contracts that platform-core seams expose to UI, audit, and provider-operation flows. ## Persisted Truth Unchanged - `ProviderConnection` remains the workspace-owned, managed-environment-scoped binding record. - `ProviderCredential` remains the optional credential record attached to one `ProviderConnection`. - `OperationRun` remains execution truth and keeps its current identity and lifecycle ownership. - `config/provider_boundaries.php` remains the single source for provider-owned versus platform-core seam classification. - No new table, registry, provider-profile entity, enum family, or taxonomy is introduced. ## Derived Runtime Contracts ### 1. Provider Connection Record **Persistence**: existing database row **Owner**: `ProviderConnection` | Field | Type | Required | Notes | |---|---|---|---| | `id` | int | yes | Existing record key | | `workspace_id` | int | yes | Existing workspace boundary | | `managed_environment_id` | int | yes | Existing managed-environment boundary; already the canonical scope anchor | | `provider` | string | yes | Current provider key (`microsoft` today) | | `display_name` | string | yes | Operator-visible connection label | | `connection_type` | enum | yes | Existing `platform` or `dedicated` connection type | | `is_default` | bool | yes | Existing default-binding flag | | `is_enabled` | bool | yes | Existing enablement flag | | `consent_status` | enum | yes | Existing consent state | | `verification_status` | enum | yes | Existing verification state | | `entra_tenant_id` | string | yes | Existing provider-owned persisted identifier; not the shared contract key after this slice | | `metadata` | array | no | Existing legacy-identity and provider-owned metadata | **Rules**: - `managed_environment_id` remains the persisted scope anchor; the stale candidate move is not reopened. - `entra_tenant_id` may remain a provider-owned stored value, but platform-core consumers must read the normalized `target_scope` contract instead of exposing this column name as shared truth. - `metadata` remains derived/provider-owned detail and must not become a second canonical shared scope contract. ### 2. Shared Target Scope Descriptor **Persistence**: derived **Owner**: `ProviderConnectionTargetScopeDescriptor` | Field | Type | Required | Notes | |---|---|---|---| | `provider` | string | yes | Shared provider key | | `scope_kind` | string | yes | Current release supports `tenant` only | | `scope_identifier` | string | yes | Neutral scope identifier used across platform-core seams | | `scope_display_name` | string | yes | Operator-facing name for the scope | | `shared_label` | string | yes | Current shared label, `Target scope` | | `shared_help_text` | string | yes | Current shared help text | **Rules**: - This is the canonical shared `target_scope` object for connection resolution, identity resolution, audit metadata, surface summaries, onboarding readiness, and provider-operation start context. - Shared `target_scope` payloads must not require `entra_tenant_id` as a top-level key. - `scope_kind` remains the current `tenant` constant; this slice does not add new scope-state machinery. ### 3. Provider Context **Persistence**: derived **Owner**: `ProviderIdentityContextMetadata` | Field | Type | Required | Notes | |---|---|---|---| | `provider` | string | yes | Provider key for the disclosed context | | `details` | list | yes | Ordered provider-owned detail items for profile, consent, audit, or troubleshooting disclosure | **Nested `provider_context.details` item** | Field | Type | Required | Notes | |---|---|---|---| | `detail_key` | string | yes | Stable provider-owned detail key such as `microsoft_tenant_id`, `admin_consent_url`, `required_permissions_url`, or `portal_domain` | | `detail_label` | string | yes | Operator/support label | | `detail_value` | string | yes | Current provider-owned value | | `visibility` | string | yes | `contextual_only`, `audit_only`, or `troubleshooting_only` | **Rules**: - `provider_context` is the canonical nested provider-owned wrapper carried by shared identity, summary, onboarding, audit, and run-context contracts. - Current Microsoft details include `microsoft_tenant_id`, `authority_tenant`, `redirect_uri`, consent links, required-permissions guidance, domains, and portal/profile links. - The detail set is intentionally provider-owned and extensible; this slice does not freeze provider context to a three-key catalog. - These values may appear in nested provider profile/context blocks or audit metadata, but they do not replace the shared `target_scope` descriptor. ### 4. Provider Identity Resolution Contract **Persistence**: derived **Owner**: `ProviderIdentityResolution` | Field | Type | Required | Notes | |---|---|---|---| | `resolved` | bool | yes | Shared resolved/blocked status | | `connection_type` | string | yes | Existing connection-type truth | | `target_scope` | object | no | Canonical shared `target_scope` descriptor | | `effective_client_identity.client_id` | string | no | Neutral shared client identity when resolved | | `effective_client_identity.credential_source` | string | yes | Shared credential source (`platform_config`, dedicated source, legacy source) | | `blocked_reason.reason_code` | string | no | Existing provider reason code when blocked | | `blocked_reason.message` | string | no | Operator-facing blocked reason message | | `provider_context` | object | yes | Nested provider-owned context wrapper with `provider` and ordered `details` | **Rules**: - The shared contract center is `target_scope`, effective client identity, credential source, and blocked reason. - Legacy `tenantContext` is an implementation concern that should be absorbed into nested provider context or authority handling, not left as the primary shared contract field name. - `clientSecret` remains runtime-only and is excluded from surface and audit contracts. - Blocked results still return `target_scope` when it can be normalized, so surfaces keep one consistent summary even on failure. ### 5. Provider Connection Surface Summary **Persistence**: derived **Owner**: `ProviderConnectionSurfaceSummary` | Field | Type | Required | Notes | |---|---|---|---| | `provider` | string | yes | Shared provider key | | `target_scope` | object | yes | Canonical shared descriptor | | `consent_state` | string | yes | Existing consent status value | | `verification_state` | string | yes | Existing verification status value | | `readiness_summary` | string | yes | Existing operator summary | | `target_scope_summary` | string | yes | Shared rendered summary for UI surfaces | | `provider_context` | object | yes | Nested provider-owned context wrapper with `provider` and ordered `details` | | `contextual_identity_line` | string | no | Optional condensed display line derived from nested provider context | | `is_enabled` | bool | yes | Existing enablement state for display logic | **Rules**: - `ProviderConnectionResource`, `ManagedTenantOnboardingWizard`, and managed-environment related-context summaries must all reuse this contract. - Default-visible content remains summary-first: target scope, readiness, consent, and verification. - Provider-specific detail is secondary and derived from nested provider context detail only. - Invalid target scope falls back to an explicit review-needed summary instead of leaking raw provider fields back into shared UI. ### 6. Onboarding Provider-Connection Readiness View **Persistence**: derived **Owner**: `ManagedTenantOnboardingWizard` | Field | Type | Required | Notes | |---|---|---|---| | `provider_connection_id` | int | yes | Selected or referenced connection | | `provider_summary` | object | yes | Reused `ProviderConnectionSurfaceSummary` payload | | `permission_overview` | object | yes | Existing required-permissions overview including nested provider-owned `required_permissions_url` guidance | **Rules**: - Onboarding must reuse the same `provider_summary.target_scope` and `target_scope_summary` contract as the provider-connections resource. - Supporting verification and permission links remain secondary and stay nested under `permission_overview.required_permissions_url` or equivalent provider-owned guidance fields. - No onboarding-only target-scope wording or fallback structure is introduced. ### 7. Provider Operation Run Context **Persistence**: derived run context in existing `OperationRun` rows **Owner**: `ProviderOperationStartGate` | Field | Type | Required | Notes | |---|---|---|---| | `execution_authority_mode` | string | yes | Existing execution-authority contract | | `required_capability` | string | no | Existing capability contract | | `provider` | string | yes | Shared provider key | | `module` | string | yes | Existing provider-operation module | | `provider_binding` | object | yes | Existing registry binding metadata | | `provider_connection_id` | int | no | Existing binding identity when present | | `target_scope` | object | yes | Canonical shared descriptor | | `provider_context` | object | no | Nested provider-owned details when required for follow-up | **Rules**: - Started and blocked runs must use the same neutral shared `target_scope` schema. - Shared run context must stop writing `target_scope.entra_tenant_id` as the primary contract. - Provider-specific fields needed for follow-up or troubleshooting move to nested `provider_context` or equivalent provider-owned metadata. - Current dedupe identity remains `provider_connection_id` plus existing identity inputs; this slice does not redefine run identity semantics. ### 8. Credential Scope Validation Invariant **Persistence**: derived runtime validation only **Owner**: `CredentialManager` | Field | Type | Required | Notes | |---|---|---|---| | `provider_connection_id` | int | yes | Existing credential owner | | `payload.client_id` | string | yes | Existing credential field | | `payload.client_secret` | string | yes | Existing credential field | | `payload.scope_assertion` | mixed | no | Existing payload assertion if present today | | `normalized_target_scope_identifier` | string | yes | Derived from canonical shared descriptor | **Rules**: - No provider-credential schema change is introduced. - If a payload carries a scope assertion, validation should compare it to the normalized target-scope identifier rather than leaking raw provider-column names into the platform-core error contract. - Neutral mismatch wording belongs in the shared seam; provider-specific values remain nested metadata only. ### 9. Provider Boundary Review Record **Persistence**: config-driven **Owner**: `config/provider_boundaries.php` | Field | Type | Required | Notes | |---|---|---|---| | `seam_key` | string | yes | Boundary seam identifier | | `owner` | string | yes | `platform_core` or `provider_owned` | | `neutral_terms` | list | yes | Shared vocabulary allowed at the seam | | `retained_provider_semantics` | list | yes | Documented provider-specific exceptions | | `follow_up_action` | string | yes | Existing review follow-up rule | **Rules**: - `provider.connection_resolution`, `provider.identity_resolution`, and `provider.operation_start_gate` remain platform-core seams and must carry only the documented provider-specific exceptions. - `provider.gateway_runtime` remains provider-owned. - `config/provider_boundaries.php` stays the single review record for this classification; the slice does not create a new taxonomy. ## Contract Flow 1. `ProviderConnection` is loaded inside its current workspace plus managed-environment scope. 2. `ProviderConnectionTargetScopeNormalizer` derives the canonical shared `target_scope` descriptor and the nested `provider_context` wrapper. 3. `ProviderConnectionResolver` validates enablement, consent, and supported binding using the normalized `target_scope` contract. 4. `ProviderIdentityResolver` emits one `ProviderIdentityResolution` result centered on target scope, effective client identity, and nested provider context. 5. `ProviderConnectionSurfaceSummary` renders the same summary contract for the provider-connections resource, onboarding, and related-context surfaces. 6. `ProviderOperationStartGate` records the same neutral `target_scope` contract into `OperationRun` context while nesting any provider-only detail under provider context. 7. Provider-owned consumers such as admin-consent URL shaping and Graph runtime mapping read the nested provider context they need without re-promoting those values into shared platform-core vocabulary. ## Deferred Boundaries - No new provider implementation is introduced. - No provider-profile table, registry, package engine, or artifact taxonomy is introduced. - No routing work from Spec `280` is absorbed. - No RBAC redesign, copy-neutralization, or cutover quality-gate work from Specs `282` through `287` is introduced.