---
id: WF-PFM-MTD-010
title: Deliver committed business events
trigger: The event pipeline separates a committed fact from asynchronous delivery.
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
implements:
- CAP-PFM-MTD-015
moves:
- STATE-PFM-MTD-008
crosses:
- SVC-PFM-MTD-custom-objects
- SVC-PFM-MTD-associations
idempotency: Envelope identities let destinations deduplicate at-least-once delivery. Expiring claims protect dispatch
  work; one dispatcher invocation and per-message failure reports govern parallelism.
concurrency: Envelope identities let destinations deduplicate at-least-once delivery. Expiring claims protect dispatch
  work; one dispatcher invocation and per-message failure reports govern parallelism.
hops:
- n: 1
  actor_or_service: Custom record store or relationship service
  action: A supported record or link mutation appends ledger and delivery work in its own transaction.
  anchor: services-platform:lib/events/platform-business-events.ts:publishBusinessEvent
  seam: sync
  on_failure: A failed or rolled-back mutation leaves no event.
  left_inconsistent: Mutation and event fact cannot commit separately.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/persistence/custom-object-records.events.integration.spec.js#publishes
    nothing when the tran
- n: 2
  actor_or_service: Publishing API function
  action: The publishing API nudges dispatch after its commit, skipping invocation while an outer transaction remains
    open.
  anchor: services-platform:lib/events/platform-business-events.ts:nudgeBusinessEventsAfterCommit
  seam: event
  on_failure: A failed nudge does not fail the saved mutation.
  left_inconsistent: The event waits for a later successful schedule.
  observer: Event delivery monitoring and the retained ledger.
  provenance: documented
  source: services-platform:docs/business-events.md#2. One event per committed change
- n: 3
  actor_or_service: Business events dispatcher
  action: Dispatch claims work, resolves runtime subscribers and router, queues each destination and removes accepted
    work; destination-free work is removed without messages.
  anchor: services-platform:modules/custom-objects/services/dispatch/business-events.ts:dispatchPlatformBusinessEvents
  seam: schedule
  on_failure: Failed queue sends retain claimed work until it becomes claimable again.
  left_inconsistent: Facts remain in the ledger, but destination-free work has no automatic later replay.
  observer: Scheduled execution logs and configured alarms.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/dispatch/business-events.integration.spec.js#keeps
    its queue row, claimed, for the next run
- n: 4
  actor_or_service: Business events consumer
  action: The consumer invokes each destination and reports individual failed messages for redelivery.
  anchor: services-platform:modules/custom-objects/services/dispatch/business-events.ts:deliverPlatformBusinessEvents
  seam: queue
  on_failure: Queue retries persist through the configured five-receive limit, then dead-letter the message.
  left_inconsistent: A persistently failed message remains undelivered even while its fact is retained.
  observer: Job or message outcomes and operational monitoring.
  provenance: test
  source: services-platform:modules/custom-objects/tests/integration/services/dispatch/business-events.integration.spec.js#answers
    the one message whose destination refus
- n: 5
  actor_or_service: Platform event intake
  action: Platform’s intake runs registered native subscribers for received envelopes.
  anchor: services-platform:modules/custom-objects/aws/lambda/EVENT_INTAKE.handler.ts
  seam: queue
  on_failure: With the pinned empty subscriber declaration, unmatched envelopes are refused.
  left_inconsistent: No native subscriber effect is produced; failure is handled by the sending queue.
  observer: Job or message outcomes and operational monitoring.
  provenance: observed
  source: services-platform:modules/custom-objects/aws/lambda/EVENT_INTAKE.handler.ts
branches:
- When runtime destination discovery returns none, dispatch removes outbox work without a message.
waits:
- A missed nudge leaves delivery waiting for a successful scheduled run.
evidence:
- 'services-platform at ad3f6a65: lib/events/platform-business-events.ts; modules/custom-objects/services/dispatch/business-events.ts;
  aws/lambda/BUSINESS_EVENTS_DISPATCHER.handler.ts, BUSINESS_EVENTS_CONSUMER.handler.ts, EVENT_INTAKE.handler.ts;
  aws/logic/business-events.lambda.ts; aws/resources/business-events.sqs.ts; docs/business-events.md'
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Deliver committed business events

## What It Does

The event pipeline separates a committed fact from asynchronous delivery. The outbox retains failed send work; the queue retries individual destination failures.

## The Flow

```mermaid
sequenceDiagram
  participant Write as Record or link write (transaction)
  participant Disp as Dispatcher (schedule, nudge)
  participant Q as Delivery queue
  participant Cons as Consumer
  participant Dest as Native intake or integration router
  Write->>Write: change, ledger fact, outbox row
  Write-)Disp: nudge after commit
  Disp->>Disp: claim waiting rows
  alt destination exists
    Disp->>Q: one message per destination
    Disp->>Disp: delete accepted rows
    Q->>Cons: batch
    Cons->>Dest: invoke
    Dest-->>Cons: ok or failure
    Cons-->>Q: report failures only
  else no destination
    Disp->>Disp: delete row, no message
  end
```

## When Something Fails

A failed or rolled-back mutation leaves no event. Mutation and event fact cannot commit separately. A failed nudge does not fail the saved mutation. The event waits for a later successful schedule. Failed queue sends retain claimed work until it becomes claimable again. Facts remain in the ledger, but destination-free work has no automatic later replay. Queue retries persist through the configured five-receive limit, then dead-letter the message. A persistently failed message remains undelivered even while its fact is retained.

## Open Design Questions

Replay to a destination registered after publication requires a decision.
