---
id: STATE-PFM-NOT-006
title: Chat and text channel identity
object: DOM-PFM-NOT-003
product_area: platform
module: notifications
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
- name: pending verification
  meaning: The channel link awaits verification.
- name: active
  meaning: The link has been activated for future channel use.
- name: unreachable
  meaning: The channel reported that the person cannot be reached.
- name: opted out
  meaning: Consent has been withdrawn by the person or carrier.
- name: revoked
  meaning: The link has ended permanently and remains historical.
transitions:
- from: pending verification
  to: active
  trigger: A caller invokes dormant identity activation.
  guard: The row must await verification; this operation does not validate a phone challenge.
  side_effects:
  - Write the verification time and reset failures; challenge verification is separate.
  who: Staff notification recipient (no route exposes it yet)
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:transitionIdentity
- from: pending verification
  to: revoked
  trigger: The pending link is removed or abandoned.
  guard: No additional condition is imposed beyond its source state.
  side_effects: []
  who: Staff notification recipient or administrator (no route exposes it yet)
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
- from: active
  to: unreachable
  trigger: A channel reports loss of reachability.
  guard: No additional condition is imposed beyond its source state.
  side_effects: []
  who: A later channel adapter
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
- from: active
  to: opted out
  trigger: The person or carrier withdraws consent.
  guard: No additional condition is imposed beyond its source state.
  side_effects: []
  who: A later channel adapter
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
- from: unreachable
  to: active
  trigger: The channel reports restored reachability or another verification.
  guard: No additional condition is imposed beyond its source state.
  side_effects: []
  who: Nightly reconciliation worker once identities exist (not built)
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
- from: opted out
  to: active
  trigger: The person restores consent.
  guard: No additional condition is imposed beyond its source state.
  side_effects: []
  who: Staff notification recipient
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
- from: active
  to: revoked
  trigger: The person or administrator removes the active link.
  guard: No additional condition is imposed beyond its source state.
  side_effects:
  - Permit another current link on that channel.
  who: Staff notification recipient or administrator
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/identities.ts:TRANSITIONS
invalid:
- from: revoked
  to: active
  why: A revoked link cannot be reactivated; linking again creates another identity.
- from: pending verification
  to: unreachable
  why: The allowed transition list requires activation before an unreachable result.
concurrency: Partial unique indexes constrain current person-channel links and workspace phone numbers.
  Conditional state updates ignore repeats and lost races. Issuing another challenge for the same person
  and number replaces previous challenges transactionally.
evidence:
- 'services-platform at ad3f6a65: modules/notifications/services/persistence/identities.ts; db/notification-channel-identities.table.ts,
  notification-sms-verifications.table.ts; docs/notifications.md §8 (not built yet).'
---
# Chat and text channel identity

## The Lifecycle

```mermaid
stateDiagram-v2
    state "pending verification" as s0
    state "active" as s1
    state "unreachable" as s2
    state "opted out" as s3
    state "revoked" as s4
    s0 --> s1
    s0 --> s4
    s1 --> s2
    s1 --> s3
    s2 --> s1
    s3 --> s1
    s1 --> s4
```

## Transitions Explained

Each transition row distinguishes the triggering caller from the condition persistence checks and the effects it writes. Dormant models describe available persistence operations rather than a deployed channel worker.

## What Cannot Happen

A revoked link cannot be reactivated; linking again creates another identity. The allowed transition list requires activation before an unreachable result.

## Concurrency and Timing

Partial unique indexes constrain current person-channel links and workspace phone numbers. Conditional state updates ignore repeats and lost races. Issuing another challenge for the same person and number replaces previous challenges transactionally.
