---
id: STATE-PFM-NOT-002
title: Notification request processing and settlement
object: DOM-PFM-NOT-003
product_area: platform
module: notifications
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
- name: queued
  meaning: Work has committed at the producer or reached the queue, but processing has not recorded an
    outcome.
- name: open
  meaning: An accepted request remains available for withdrawal or replacement.
- name: settled
  meaning: An accepted request has finished its expiry processing and cannot be withdrawn.
- name: no recipients
  meaning: Audience resolution found no eligible people.
- name: invalid
  meaning: Validation rejected the definition, payload or audience and retained the problems.
- name: expired
  meaning: The processing deadline passed before acceptance.
- name: cancelled
  meaning: An early withdrawal left a cancellation record, or retirement closed an accepted request.
- name: superseded
  meaning: Withdrawal or replacement ended an accepted request and its unsent work.
transitions:
- from: queued
  to: open
  trigger: The processor accepts queued work.
  guard: The definition is active, cancellation does not apply, timing permits processing, data validates,
    and the allowed audience has one to two hundred eligible people.
  side_effects:
  - Create the request, notices, deliveries and dispatch work atomically.
  - Record console delivery immediately.
  - When occurrence replacement applies, supersede the preceding open request.
  who: Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#writes
    the console delivery delivered at once and records every other supported channel as not available
    until its milestone
- from: queued
  to: queued
  trigger: The processor encounters work scheduled for later.
  guard: The earliest processing time has not arrived.
  side_effects:
  - Defer without an outcome; near the receive limit, publish a fresh delayed copy.
  who: Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/dispatch/process-request-batch.integration.spec.js#replaces
    a request that is not due with a fresh delayed copy when the next receive would be the last
- from: queued
  to: no recipients
  trigger: Audience resolution produces an empty result.
  guard: Earlier acceptance checks have passed.
  side_effects:
  - Keep workspace-isolation exclusions with the request.
  who: Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#notifies
    nobody when everyone named is outside the organization, recording no_recipients with the refusal
- from: queued
  to: invalid
  trigger: Acceptance validation rejects the request.
  guard: The definition, schema or audience checks fail.
  side_effects:
  - Store field-level problems for History.
  who: Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#records
    an unknown definition as invalid
- from: queued
  to: expired
  trigger: Processing or reconciliation detects an elapsed deadline.
  guard: The explicit deadline or definition-relative age limit has elapsed.
  side_effects:
  - Record expiry without creating a notice.
  who: Notification processing worker; nightly reconciliation
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/orchestrate-request.integration.spec.js#expires
    a request older than its definition’s expires_after from the instant the producer wrote it
- from: queued
  to: cancelled
  trigger: Withdrawal arrives before acceptance, or processing discovers a later replacement-key cancellation.
  guard: The cancellation identifies the request or its replacement key.
  side_effects:
  - Retain the cancellation outcome without notifying anyone.
  who: Producer's cancel; Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/cancel-and-supersede.integration.spec.js#leaves
    nobody told and records the request cancelled when the cancel names the publish’s key
- from: open
  to: superseded
  trigger: An open request is withdrawn or replaced by an accepted occurrence.
  guard: The original request is accepted and has not been settled.
  side_effects:
  - Cancel unsent deliveries and remove their dispatch work.
  - Mark notices as superseded, including notices delivered in the console.
  - Reassign folded notices to the oldest remaining open contributing request.
  - Close the original request.
  who: Producer's cancel or replacement; Notification processing worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/cancel-and-supersede.integration.spec.js#marks
    the instance superseded, leaves it readable and takes it out of the unread count
- from: open
  to: settled
  trigger: The nightly sweep completes expired work.
  guard: The deadline has passed and no delivery remains queued, deferred or sending.
  side_effects:
  - Expire unsent deliveries first; expire a notice when none of its channels has sent.
  who: Nightly reconciliation worker
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/reconcile/reconcile-tenant.integration.spec.js#settles
    a request past its expiry whose notification was delivered, so a late cancel reaches nothing
- from: open
  to: cancelled
  trigger: Registration retires the definition.
  guard: The workspace is operational and the request is accepted but unsettled.
  side_effects:
  - Close the request as cancelled while preserving its notices and delivery states.
  who: Registration intake
  provenance: observed
  source: services-platform:modules/notifications/services/persistence/requests.ts:cancelOpenRequestsOfDefinition
invalid:
- from: settled
  to: superseded
  why: A settled request is excluded from withdrawal.
- from: no recipients
  to: open
  why: An existing non-accepted outcome prevents another acceptance attempt.
- from: invalid
  to: open
  why: Correcting rejected input requires another publication.
- from: open
  to: queued
  why: Repeated queue work resumes dispatch rather than removing the existing outcome.
concurrency: The derived request identity prevents duplicate outcomes. Conditional settlement coordinates
  withdrawal with reconciliation. An early cancellation persists as a tombstone that later publication
  checks, so processing does not require queue order.
invariants:
- INV-DOM-PFM-NOT-003-02
- INV-DOM-PFM-NOT-003-05
evidence:
- 'services-platform at ad3f6a65: modules/notifications/services/orchestration/orchestrate-request.ts
  (header and supersedeRequest); services/persistence/requests.ts; services/reconcile/reconcile-tenant.ts;
  notifications.settings.ts:REQUEST_OUTCOMES.'
---
# Notification request processing and settlement

## The Lifecycle

```mermaid
stateDiagram-v2
    state "queued" as s0
    state "open" as s1
    state "settled" as s2
    state "no recipients" as s3
    state "invalid" as s4
    state "expired" as s5
    state "cancelled" as s6
    state "superseded" as s7
    s0 --> s1
    s0 --> s0
    s0 --> s3
    s0 --> s4
    s0 --> s5
    s0 --> s6
    s1 --> s7
    s1 --> s2
    s1 --> s6
```

## Transitions Explained

The transition rows describe stored state changes, their checks and their recorded effects. A queue receive, provider outcome and staff action can reach different lifecycle boundaries.

## What Cannot Happen

A settled request is excluded from withdrawal. An existing non-accepted outcome prevents another acceptance attempt. Correcting rejected input requires another publication. Repeated queue work resumes dispatch rather than removing the existing outcome.

## Concurrency and Timing

The derived request identity prevents duplicate outcomes. Conditional settlement coordinates withdrawal with reconciliation. An early cancellation persists as a tombstone that later publication checks, so processing does not require queue order.
