---
id: STATE-PFM-INT-003
title: Connection lifecycle
object: DOM-PFM-INT-002
product_area: platform
module: integrations
revision: 1
status: draft
design_intent: confirmed
implementation_evidence: observed
origin: 'docs/milestones/INTG-M1-find-install-connect.md#Decisions D7, D9, D10 (INTG-M1 Product Accepted)'
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: pending_auth
    meaning: The link awaits entered credentials or provider authorization.
  - name: verifying
    meaning: Verification work is pending or running for the account.
  - name: active
    meaning: Verification succeeded and the account is usable.
  - name: degraded
    meaning: The account remains usable but carries a health warning.
  - name: failed_verification
    meaning: The account failed verification and cannot serve work.
  - name: reauth_required
    meaning: Credential refusal prevents work until fresh authorization is verified.
  - name: suspended
    meaning: The account is deliberately paused and ineligible for calls.
  - name: disconnected
    meaning: The link is permanently ended; endpoints are disabled and credentials revoked.
transitions:
  - from: pending_auth
    to: verifying
    trigger: Authentication becomes available
    guard: 'Entered credentials, sign-in tokens or platform-account setup supply authentication'
    side_effects:
      - Request verification and commit audit and binding reassessment.
    who: Credential store or creation
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: verifying
    to: active
    trigger: Complete first verification successfully
    guard: The provider confirms an account that can be recorded without duplication
    side_effects:
      - 'Save identity, features and environment and provision declared endpoints.'
    who: Verification job
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/connection-jobs.integration.spec.js#becomes
      active with the account and every declared feature verified
  - from: verifying
    to: failed_verification
    trigger: Complete verification unsuccessfully
    guard: Provider refusal or duplicate account identity prevents activation
    side_effects:
      - Save the check’s refusal reason.
    who: Verification job
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/db/integration-connections.table.integration.spec.js#refuses
      the same provider account connected twice under the installation
  - from: failed_verification
    to: verifying
    trigger: Request verification after failure
    guard: A person requests another check or supplies replacement authentication
    side_effects:
      - Submit verification work.
    who: Integration administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: active
    to: degraded
    trigger: Record an unhealthy result
    guard: An eligible health or scheduled verification check fails
    side_effects:
      - Keep bindings eligible while exposing a warning.
    who: Health or verification job
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/connection-jobs.integration.spec.js#degrades
      an active connection whose provider is unhealthy
  - from: degraded
    to: active
    trigger: Record a healthy result
    guard: An eligible health or scheduled verification check succeeds
    side_effects:
      - Clear the degraded status.
    who: Health or verification job
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/connection-jobs.integration.spec.js#degrades
      an active connection whose provider is unhealthy
  - from: active
    to: reauth_required
    trigger: Record credential refusal
    guard: Refresh or verification determines that authentication was rejected
    side_effects:
      - Invalidate dependent bindings and request mail after commit.
    who: Refresh pass or verification job
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/credentials/refresh.integration.spec.js#makes
      one token request when two refreshes of a connection run at once
  - from: degraded
    to: reauth_required
    trigger: Record credential refusal on a degraded account
    guard: The provider rejects the account’s authentication
    side_effects:
      - Invalidate dependent bindings and request mail after commit.
    who: Refresh pass or verification job
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: reauth_required
    to: verifying
    trigger: Receive fresh authorization
    guard: A replacement credential or completed sign-in is supplied
    side_effects:
      - Submit verification work before allowing calls.
    who: Integration credential administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: active
    to: suspended
    trigger: Pause a usable account
    guard: An administrator or installation pause requests suspension
    side_effects:
      - 'Invalidate bindings and save suspension actor, reason and cause.'
    who: Integration administrator or Rhythm staff
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/installations/history-and-security-trail.integration.spec.js#refuses
      a suspension of a connection that is not active, recording it in neither trail
  - from: degraded
    to: suspended
    trigger: Pause a degraded account
    guard: The same suspension rules apply to degraded accounts
    side_effects:
      - Invalidate its current bindings.
    who: Integration administrator or Rhythm staff
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: suspended
    to: active
    trigger: Restore a paused account
    guard: The account remains suspended
    side_effects:
      - Restore eligible bindings
      - Later checks can still degrade it.
    who: Integration administrator or Rhythm staff
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/installations/history-and-security-trail.integration.spec.js#refuses
      a suspension of a connection that is not active, recording it in neither trail
  - from: active
    to: disconnected
    trigger: Close a healthy account
    guard: No current binding references the account
    side_effects:
      - 'Disable endpoints, revoke credentials, clear notices and record attribution.'
    who: Integration administrator
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/transition.integration.spec.js#disables
      the connection’s webhook endpoints
  - from: degraded
    to: disconnected
    trigger: Close a degraded account
    guard: No current binding references the account
    side_effects:
      - Apply the ordinary disconnection cleanup.
    who: Integration administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:disconnectConnection'
  - from: suspended
    to: disconnected
    trigger: Close a paused account
    guard: No current binding references the account
    side_effects:
      - Apply the ordinary disconnection cleanup.
    who: Integration administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: reauth_required
    to: disconnected
    trigger: Close an account requiring authorization
    guard: No current binding references the account
    side_effects:
      - Apply the ordinary disconnection cleanup.
    who: Integration administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
  - from: failed_verification
    to: disconnected
    trigger: Close after failed re-verification
    guard: Prior successful verification exists and no current binding references the account
    side_effects:
      - Apply the ordinary disconnection cleanup.
    who: Integration administrator
    provenance: observed
    source: 'services-platform:modules/integrations/services/connections/transition.ts:CONNECTION_TRANSITIONS'
    note: >-
      This restoration path applies to an account verified earlier; its claimed milestone decision is absent
      from the cited decision list.
  - from: pending_auth
    to: disconnected
    trigger: Abandon initial authentication
    guard: The account has no successful verification in history
    side_effects:
      - Record a discard reason and disable endpoints and credentials.
    who: Integration administrator
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/disconnect-discard-uninstall.integration.spec.js#ends
      a pending_auth connection disconnected, by the caller, with a reason saying it was discarded before it
      was ever connected
  - from: verifying
    to: disconnected
    trigger: Abandon first verification
    guard: The account has never passed verification
    side_effects:
      - Apply unfinished-link discard cleanup.
    who: Integration administrator
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/disconnect-discard-uninstall.integration.spec.js#ends
      a pending_auth connection disconnected, by the caller, with a reason saying it was discarded before it
      was ever connected
  - from: failed_verification
    to: disconnected
    trigger: Abandon unsuccessful initial verification
    guard: No prior successful verification exists
    side_effects:
      - Apply unfinished-link discard cleanup.
    who: Integration administrator
    provenance: test
    source: >-
      services-platform:modules/integrations/tests/integration/services/connections/disconnect-discard-uninstall.integration.spec.js#ends
      a pending_auth connection disconnected, by the caller, with a reason saying it was discarded before it
      was ever connected
invalid:
  - from: disconnected
    to: active
    why: Final disconnection requires a new account-link record for another setup.
  - from: pending_auth
    to: active
    why: Initial activation requires successful verification.
  - from: suspended
    to: degraded
    why: Paused accounts are excluded from normal health degradation checks.
  - from: reauth_required
    to: active
    why: Fresh authorization must pass verification before use.
  - from: degraded
    to: verifying
    why: >-
      Periodic checks retain eligible account status rather than putting degraded accounts into
      first-verification status.
concurrency: >-
  Named transitions serialize on account rows and retain both audits and binding effects together. Open check
  requests reuse existing work. Scheduled checks exclude paused accounts; result writes compare the status
  they observed, and administrator mail follows commit.
invariants:
  - INV-DOM-PFM-INT-002-01
  - INV-DOM-PFM-INT-002-02
  - INV-DOM-PFM-INT-002-03
  - INV-DOM-PFM-INT-002-04
  - INV-DOM-PFM-INT-002-08
evidence:
  - >-
    services-platform at ad3f6a65: modules/integrations/services/connections/transition.ts;
    tests/unit/services/connection-state-machine.spec.ts; docs/integrations/README.md (The connection state
    machine)
---

# Connection lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  state "pending_auth" as s0
  state "verifying" as s1
  state "active" as s2
  state "degraded" as s3
  state "failed_verification" as s4
  state "reauth_required" as s5
  state "suspended" as s6
  state "disconnected" as s7
  s0 --> s1: Authentication becomes available
  s1 --> s2: Complete first verification successfully
  s1 --> s4: Complete verification unsuccessfully
  s4 --> s1: Request verification after failure
  s2 --> s3: Record an unhealthy result
  s3 --> s2: Record a healthy result
  s2 --> s5: Record credential refusal
  s3 --> s5: Record credential refusal on a degraded account
  s5 --> s1: Receive fresh authorization
  s2 --> s6: Pause a usable account
  s3 --> s6: Pause a degraded account
  s6 --> s2: Restore a paused account
  s2 --> s7: Close a healthy account
  s3 --> s7: Close a degraded account
  s6 --> s7: Close a paused account
  s5 --> s7: Close an account requiring authorization
  s4 --> s7: Close after failed re-verification
  s0 --> s7: Abandon initial authentication
  s1 --> s7: Abandon first verification
  s4 --> s7: Abandon unsuccessful initial verification
```

## Transitions Explained

Authentication starts verification for a new link; successful checks make it usable and later health checks can degrade or restore it. Credential refusal requires fresh authorization. Pausing retains the account and closing ends it permanently; unfinished links have a guarded discard path.

## What Cannot Happen

Final disconnection requires a new account-link record for another setup. Initial activation requires successful verification. Paused accounts are excluded from normal health degradation checks. Fresh authorization must pass verification before use. Periodic checks retain eligible account status rather than putting degraded accounts into first-verification status.

## Concurrency and Timing

Named transitions serialize on account rows and retain both audits and binding effects together. Open check requests reuse existing work. Scheduled checks exclude paused accounts; result writes compare the status they observed, and administrator mail follows commit.
