---
id: STATE-PFM-INT-012
title: Delivery progress
object: DOM-PFM-INT-004
product_area: platform
module: integrations
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
  - name: pending
    meaning: The projected change awaits push processing or a pull cursor.
  - name: delivered
    meaning: The adapter acknowledged the change or a cursor covered it.
  - name: retrying
    meaning: Classified transient failure has another delivery attempt due.
  - name: failed
    meaning: Configuration or consent failure stopped this delivery and an operator can retry it.
  - name: dead
    meaning: Retryable attempts were exhausted or a permanent attempt failure ended delivery.
  - name: skipped_filter
    meaning: The change did not pass the subscription filter and has no queued delivery.
transitions:
  - from: pending
    to: delivered
    trigger: Acknowledge initial push
    guard: The adapter returns a successful handled response
    side_effects:
      - Save the acknowledgement.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts'
  - from: pending
    to: retrying
    trigger: Defer unsuccessful push
    guard: The classified error allows another attempt
    side_effects:
      - Write next delivery dispatch work.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts'
  - from: retrying
    to: delivered
    trigger: Acknowledge a later push
    guard: The adapter returns a successful handled response
    side_effects:
      - Reset the subscription’s consecutive dead count.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts:processDelivery'
  - from: retrying
    to: dead
    trigger: End delivery retries
    guard: The sixth attempt fails or failure is permanently non-retryable
    side_effects:
      - Record a dead outcome for the subscription threshold.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts'
  - from: pending
    to: delivered
    trigger: Advance a pull cursor
    guard: The authorized adapter advances beyond pending deliveries
    side_effects:
      - Mark covered pending records delivered.
    who: Adapter callback
    provenance: observed
    source: 'services-platform:modules/integrations/aws/api/gateway.routes.ts:writePullCursor'
  - from: dead
    to: pending
    trigger: Restart dead delivery
    guard: An authorized operator requests retry
    side_effects:
      - Reset attempt progression and queue work with history.
    who: Executions operator
    provenance: observed
    source: 'services-platform:modules/integrations/services/events/event-operations.ts:retryDelivery'
  - from: failed
    to: pending
    trigger: Restart failed delivery
    guard: An authorized operator requests retry
    side_effects:
      - Reset attempt progression and queue work.
    who: Executions operator
    provenance: observed
    source: 'services-platform:modules/integrations/services/events/event-operations.ts:retryDelivery'
  - from: retrying
    to: retrying
    trigger: Schedule a further delivery attempt
    guard: Another retryable failure occurs before the attempt ceiling
    side_effects:
      - Save the outcome and any permitted next dispatch.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts:processDelivery'
  - from: pending
    to: dead
    trigger: Fail permanently on the first attempt
    guard: The classified failure permits no retry
    side_effects:
      - Save the outcome and any permitted next dispatch.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts:processDelivery'
  - from: pending
    to: failed
    trigger: Refuse initial delivery after configuration loss
    guard: 'The subscription or account is gone, or accepted event access is absent'
    side_effects:
      - Save the outcome and any permitted next dispatch.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts:processDelivery'
  - from: retrying
    to: failed
    trigger: Refuse later delivery after configuration loss
    guard: 'The subscription or account is gone, or accepted event access is absent'
    side_effects:
      - Save the outcome and any permitted next dispatch.
    who: Delivery worker
    provenance: observed
    source: 'services-platform:modules/integrations/services/subscriptions/delivery-worker.ts:processDelivery'
  - from: delivered
    to: pending
    trigger: Restart eligible delivery work
    guard: An authorized operator requests retry or bounded window replay
    side_effects:
      - 'Reset attempts and errors, audit the request and nudge dispatch.'
    who: Executions operator
    provenance: observed
    source: 'services-platform:modules/integrations/services/events/event-operations.ts:retryDelivery'
  - from: retrying
    to: pending
    trigger: Restart eligible delivery work
    guard: An authorized operator requests retry or bounded window replay
    side_effects:
      - 'Reset attempts and errors, audit the request and nudge dispatch.'
    who: Executions operator
    provenance: observed
    source: 'services-platform:modules/integrations/services/events/event-operations.ts:retryDelivery'
invalid:
  - from: skipped_filter
    to: pending
    why: Changing a filter does not reconstruct a delivery previously recorded as filtered out.
concurrency: >-
  A subscription-change key protects delivery identity and a worker claims each numbered attempt. External
  delivery can repeat after lost acknowledgement. Backoff waits use one, five and thirty minutes, two hours
  and six hours, with no ordering guarantee between different deliveries.
invariants:
  - INV-DOM-PFM-INT-004-07
  - INV-DOM-PFM-INT-004-08
evidence:
  - >-
    services-platform at ad3f6a65: modules/integrations/db/integration-deliveries.table.ts,
    integration-delivery-keys.table.ts; services/subscriptions/change-event-handler.ts, delivery-worker.ts;
    services/events/event-operations.ts;
    services-platform:docs/milestones/INTG-M3-webhooks-events-deliveries.md (status Proposed)
---

# Delivery progress

## The Lifecycle

```mermaid
stateDiagram-v2
  state "pending" as s0
  state "delivered" as s1
  state "retrying" as s2
  state "failed" as s3
  state "dead" as s4
  state "skipped_filter" as s5
  s0 --> s1: Acknowledge initial push
  s0 --> s2: Defer unsuccessful push
  s2 --> s1: Acknowledge a later push
  s2 --> s4: End delivery retries
  s0 --> s1: Advance a pull cursor
  s4 --> s0: Restart dead delivery
  s3 --> s0: Restart failed delivery
  s2 --> s2: Schedule a further delivery attempt
  s0 --> s4: Fail permanently on the first attempt
  s0 --> s3: Refuse initial delivery after configuration loss
  s2 --> s3: Refuse later delivery after configuration loss
  s1 --> s0: Restart eligible delivery work
  s2 --> s0: Restart eligible delivery work
```

## Transitions Explained

Push acknowledgement and pull-cursor coverage both complete delivery. Classified errors can retry, become dead or fail because configuration no longer permits delivery. Supported operator retries restart attempts. Window replay covers retained deliveries rather than fabricating changes skipped while paused.

## What Cannot Happen

Changing a filter does not reconstruct a delivery previously recorded as filtered out.

## Concurrency and Timing

A subscription-change key protects delivery identity and a worker claims each numbered attempt. External delivery can repeat after lost acknowledgement. Backoff waits use one, five and thirty minutes, two hours and six hours, with no ordering guarantee between different deliveries.
