openapi: 3.1.0
info:
  title: Canonical Provider Connection State Cleanup Internal Contract
  version: 0.1.0
  summary: Internal planning contract for the hard cut from legacy provider status and health to canonical lifecycle, consent, and verification
  description: |
    This contract is an internal planning artifact for Spec 188. The affected
    routes continue to render HTML. The schemas below describe the canonical
    provider-state contract that must be derivable before rendering and before
    runtime gates execute. Legacy `status` and `health_status` do not appear in
    any schema because the feature requires a hard cut with no compatibility
    payload.
servers:
  - url: /internal
x-cutover-order:
  - runtime_readers
  - runtime_writers
  - shared_presenters_and_badges
  - factories_helpers_and_tests
  - schema_removal
x-runtime-readers:
  - surface: resolver_and_runtime_gates
    guardScope:
      - app/Services/Providers/ProviderConnectionResolver.php
      - app/Jobs/ScanEntraAdminRolesJob.php
      - app/Filament/Resources/ProviderConnectionResource.php
    expectedContract:
      - lifecycle_reads_is_enabled_only
      - consent_inference_reads_consent_status_only
      - verification_inference_reads_verification_status_only
  - surface: tenant_and_system_summaries
    guardScope:
      - app/Filament/Resources/TenantResource.php
      - resources/views/filament/infolists/entries/provider-connection-state.blade.php
      - app/Filament/System/Pages/Directory/Tenants.php
      - app/Filament/System/Pages/Directory/ViewTenant.php
      - resources/views/filament/system/pages/directory/view-tenant.blade.php
    expectedContract:
      - helper_payload_has_no_legacy_status_keys
      - system_rollups_derive_from_verification_and_permission_truth
      - admin_and_system_planes_tell_the_same_provider_state_story
x-runtime-writers:
  - surface: onboarding_and_consent_bootstrap
    writerScope:
      - app/Http/Controllers/TenantOnboardingController.php
      - app/Http/Controllers/AdminConsentCallbackController.php
      - app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php
    expectedContract:
      - initialize_is_enabled
      - initialize_or_update_consent_status
      - initialize_verification_status_without_legacy_projection
  - surface: verification_and_health_check
    writerScope:
      - app/Services/Verification/StartVerification.php
      - app/Jobs/ProviderConnectionHealthCheckJob.php
      - app/Services/Providers/Contracts/HealthResult.php
      - app/Services/Providers/MicrosoftProviderHealthCheck.php
      - app/Services/Providers/ProviderConnectionStateProjector.php
    expectedContract:
      - verification_contract_uses_canonical_status
      - verification_writes_update_only_canonical_fields_and_diagnostics
  - surface: provider_mutations
    writerScope:
      - app/Services/Providers/ProviderConnectionMutationService.php
      - app/Filament/Resources/ProviderConnectionResource.php
    expectedContract:
      - enable_disable_mutations_write_lifecycle_not_legacy_status
      - credential_mutations_reset_or_block_verification_without_legacy_projection
x-legacy-removal-scope:
  removed_columns:
    - provider_connections.status
    - provider_connections.health_status
  removed_badge_domains:
    - provider_connection.status
    - provider_connection.health
  removed_helper_keys:
    - status
    - health_status
paths:
  /admin/provider-connections:
    get:
      summary: Render the canonical provider-connections list with lifecycle, consent, and verification as the only state axes
      operationId: viewCanonicalProviderConnections
      responses:
        '200':
          description: Provider-connections list rendered from canonical provider-state truth only
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.provider-connections-canonical+json:
              schema:
                $ref: '#/components/schemas/ProviderConnectionListTruthBundle'
        '302':
          description: Existing admin tenant-scoping redirects still apply
        '404':
          description: Workspace or tenant scope is outside entitlement
  /admin/provider-connections/{record}:
    get:
      summary: Render canonical provider connection detail without legacy provider status or health
      operationId: viewCanonicalProviderConnection
      parameters:
        - name: record
          in: path
          required: true
          schema:
            type:
              - integer
              - string
      responses:
        '200':
          description: Provider connection detail rendered from lifecycle, consent, verification, and diagnostics only
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.provider-connection-canonical+json:
              schema:
                $ref: '#/components/schemas/ProviderConnectionDetailTruthModel'
        '403':
          description: Actor is in scope but lacks the capability required for protected actions
        '404':
          description: Provider connection is outside entitlement scope
  /admin/provider-connections/{record}/edit:
    get:
      summary: Render canonical provider connection edit context with lifecycle, consent, and verification
      operationId: editCanonicalProviderConnection
      parameters:
        - name: record
          in: path
          required: true
          schema:
            type:
              - integer
              - string
      responses:
        '200':
          description: Provider connection edit rendered without legacy status or health fields
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.provider-connection-edit-canonical+json:
              schema:
                $ref: '#/components/schemas/ProviderConnectionDetailTruthModel'
        '403':
          description: Actor is in scope but lacks manage capability
        '404':
          description: Provider connection is outside entitlement scope
  /admin/tenants/{tenant}:
    get:
      summary: Render tenant detail provider summary from canonical provider-state truth only
      operationId: viewCanonicalTenantProviderSummary
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Tenant detail rendered with a canonical provider summary and no legacy provider-state payload
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.tenant-provider-summary-canonical+json:
              schema:
                $ref: '#/components/schemas/TenantProviderSummary'
        '404':
          description: Tenant is outside entitlement scope
  /system/directory/tenants:
    get:
      summary: Render system tenant directory with health rollups derived from canonical verification and permission truth
      operationId: viewSystemTenantDirectoryCanonicalHealth
      responses:
        '200':
          description: System directory list rendered without legacy provider health aggregation
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.system-tenant-directory-canonical+json:
              schema:
                $ref: '#/components/schemas/SystemTenantDirectoryTruthBundle'
        '404':
          description: Platform actor lacks directory access or tenant scope is unavailable
  /system/directory/tenants/{tenant}:
    get:
      summary: Render system tenant detail with canonical provider rows
      operationId: viewSystemTenantCanonicalProviderRows
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type:
              - integer
              - string
      responses:
        '200':
          description: System tenant detail rendered with canonical provider-state rows only
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.system-tenant-canonical-provider-rows+json:
              schema:
                $ref: '#/components/schemas/SystemTenantDetailTruthModel'
        '404':
          description: Platform actor lacks directory access or tenant is unavailable
components:
  schemas:
    LifecycleState:
      type: string
      enum:
        - enabled
        - disabled
    ProviderConsentState:
      type: string
      enum:
        - unknown
        - required
        - granted
        - failed
        - revoked
    ProviderVerificationState:
      type: string
      enum:
        - unknown
        - pending
        - healthy
        - degraded
        - blocked
        - error
    ProviderDiagnostics:
      type: object
      required:
        - migrationReviewRequired
      properties:
        lastCheckedAt:
          type:
            - string
            - 'null'
        lastErrorReasonCode:
          type:
            - string
            - 'null'
        lastErrorMessage:
          type:
            - string
            - 'null'
        consentErrorCode:
          type:
            - string
            - 'null'
        consentErrorMessage:
          type:
            - string
            - 'null'
        migrationReviewRequired:
          type: boolean
    CanonicalProviderConnectionState:
      type: object
      required:
        - lifecycle
        - isEnabled
        - consentStatus
        - verificationStatus
        - diagnostics
      properties:
        lifecycle:
          $ref: '#/components/schemas/LifecycleState'
        isEnabled:
          type: boolean
        consentStatus:
          oneOf:
            - $ref: '#/components/schemas/ProviderConsentState'
            - type: 'null'
        verificationStatus:
          oneOf:
            - $ref: '#/components/schemas/ProviderVerificationState'
            - type: 'null'
        diagnostics:
          $ref: '#/components/schemas/ProviderDiagnostics'
    ProviderConnectionRow:
      type: object
      required:
        - id
        - displayName
        - provider
        - connectionType
        - isDefault
        - state
      properties:
        id:
          type: integer
        tenantLabel:
          type:
            - string
            - 'null'
        displayName:
          type: string
        provider:
          type: string
        connectionType:
          type: string
        isDefault:
          type: boolean
        state:
          $ref: '#/components/schemas/CanonicalProviderConnectionState'
    ProviderConnectionListTruthBundle:
      type: object
      required:
        - rows
      properties:
        rows:
          type: array
          items:
            $ref: '#/components/schemas/ProviderConnectionRow'
    ProviderConnectionDetailTruthModel:
      type: object
      required:
        - id
        - displayName
        - provider
        - connectionType
        - isDefault
        - state
      properties:
        id:
          type: integer
        displayName:
          type: string
        provider:
          type: string
        connectionType:
          type: string
        isDefault:
          type: boolean
        effectiveAppId:
          type:
            - string
            - 'null'
        effectiveAppSource:
          type:
            - string
            - 'null'
        state:
          $ref: '#/components/schemas/CanonicalProviderConnectionState'
    TenantProviderSummary:
      type: object
      required:
        - state
        - ctaUrl
        - needsDefaultConnection
      properties:
        state:
          type: string
          enum:
            - missing
            - configured
            - default_configured
        ctaUrl:
          type: string
        needsDefaultConnection:
          type: boolean
        displayName:
          type:
            - string
            - 'null'
        provider:
          type:
            - string
            - 'null'
        canonicalState:
          oneOf:
            - $ref: '#/components/schemas/CanonicalProviderConnectionState'
            - type: 'null'
    SystemTenantDirectoryRow:
      type: object
      required:
        - tenantId
        - tenantLabel
        - workspaceLabel
        - providerConnectionsCount
        - criticalProviderCount
        - warningProviderCount
        - missingPermissionCount
        - systemHealth
      properties:
        tenantId:
          type: integer
        tenantLabel:
          type: string
        workspaceLabel:
          type: string
        providerConnectionsCount:
          type: integer
        criticalProviderCount:
          type: integer
        warningProviderCount:
          type: integer
        missingPermissionCount:
          type: integer
        systemHealth:
          type: string
    SystemTenantDirectoryTruthBundle:
      type: object
      required:
        - rows
      properties:
        rows:
          type: array
          items:
            $ref: '#/components/schemas/SystemTenantDirectoryRow'
    SystemTenantDetailTruthModel:
      type: object
      required:
        - tenantId
        - tenantLabel
        - providerConnections
      properties:
        tenantId:
          type: integer
        tenantLabel:
          type: string
        providerConnections:
          type: array
          items:
            $ref: '#/components/schemas/ProviderConnectionRow'