---
id: WF-PFM-NOT-004
title: Withdraw or replace a notice
trigger: A producer or system caller withdraws notification work, or a later accepted occurrence replaces
  it.
product_area: platform
module: notifications
revision: 1
status: draft
design_intent: confirmed
origin: PLAT-M23 assumption A6 approved (a cancellation before dispatch means nobody is told; after dispatch
  the delivered item is marked no longer applies), services-platform:docs/milestones/plans/PLAT-M23-plan.humanized.md#4.
  Assumptions
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
- CAP-PFM-NOT-006
- CAP-PFM-NOT-005
- CAP-PFM-NOT-014
moves:
- STATE-PFM-NOT-002
- STATE-PFM-NOT-003
- STATE-PFM-NOT-005
crosses:
- SVC-PFM-NOT-notifications
hops:
- n: 1
  actor_or_service: Notification producer
  action: Commit cancellation work identifying the publication or replacement key alongside the producer
    change.
  anchor: '@rhythmsoftware/macroservice-notifications:cancelNotification'
  seam: sync
  on_failure: The caller transaction determines rollback.
  left_inconsistent: No independently committed cancellation entry.
  observer: Producer logs.
  provenance: documented
  source: services-platform:docs/notifications.md#9. Producers
- n: 2
  actor_or_service: Dispatcher and request consumer
  action: Dispatch cancellation and locate matching accepted open requests.
  anchor: services-platform:modules/notifications/services/orchestration/orchestrate-request.ts
  seam: queue
  on_failure: Retry through queue redelivery.
  left_inconsistent: No partial withdrawal.
  observer: Cancellation outcome metric.
  provenance: observed
  source: services-platform:modules/notifications/services/orchestration/orchestrate-request.ts
- n: 3
  actor_or_service: Request consumer
  action: When no matching request is open, persist a tombstone for later publication checks.
  anchor: services-platform:modules/notifications/services/persistence/requests.ts:findCancellationBySupersedeKey
  seam: sync
  on_failure: Retry the queue item.
  left_inconsistent: No partially recorded tombstone.
  observer: Cancelled outcome in History.
  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
- n: 4
  actor_or_service: Request consumer
  action: Atomically cancel unsent channels, remove dispatch work, transfer folded ownership to the oldest
    remaining contributor where possible, supersede other notices and settle the request.
  anchor: services-platform:modules/notifications/services/orchestration/orchestrate-request.ts:supersedeRequest
  seam: sync
  on_failure: Roll back and retry.
  left_inconsistent: Prior sends remain visible; redacted folded content may retain its old wording.
  observer: Inbox applicability labels and unread totals.
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/orchestration/cancel-and-supersede.integration.spec.js#keeps
    the notification when the first of its requests ends, handing it to the next and dropping the count
- n: 5
  actor_or_service: Chat delivery consumer
  action: Before sending queued work, detect a superseded notice and cancel the delivery.
  anchor: services-platform:modules/notifications/services/dispatch/deliver-delivery.ts:deliverQueuedDelivery
  seam: queue
  on_failure: Acknowledge the item after terminal handling.
  left_inconsistent: No new send is attempted.
  observer: Cancelled delivery history.
  provenance: test
  source: services-platform:modules/notifications/tests/integration/services/dispatch/deliver-delivery.integration.spec.js#cancels,
    not sends, a delivery whose notification was superseded after it was queued
idempotency: Settled requests are skipped, and cancellation tombstones persist under their derived identity;
  later publications are not retroactively cancelled.
concurrency: Conditional settlement coordinates reconciliation with withdrawal; an already claimed send
  can still complete.
branches:
- Occurrence replacement withdraws prior work within acceptance.
- Definition retirement closes requests without the same notice-withdrawal steps.
waits:
- An accepted request remains withdrawable until settlement after expiry.
evidence:
- 'services-platform at ad3f6a65: modules/notifications/services/orchestration/orchestrate-request.ts
  (cancel path, supersedeRequest, rerenderMessage); services/persistence/{requests,instances,deliveries}.ts.'
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-CRY-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-002, TC-LOG-003, 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-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---
# Withdraw or replace a notice

## What It Does

A producer or system caller withdraws notification work, or a later accepted occurrence replaces it.

## The Flow

```mermaid
flowchart TD
    h0["Commit cancellation work identifying the publication or replacement key alongside the producer change"]
    h1["Dispatch cancellation and locate matching accepted open requests"]
    h0 --> h1
    h2["When no matching request is open, persist a tombstone for later publication checks"]
    h1 --> h2
    h3["Atomically cancel unsent channels, remove dispatch work, transfer folded ownership to the oldest remaining contribu"]
    h2 --> h3
    h4["Before sending queued work, detect a superseded notice and cancel the delivery"]
    h3 --> h4
```

## When Something Fails

The hop rows identify each retry boundary, any state left behind and the available observer. Settled requests are skipped, and cancellation tombstones persist under their derived identity; later publications are not retroactively cancelled. Conditional settlement coordinates reconciliation with withdrawal; an already claimed send can still complete.

## Open Design Questions

Occurrence replacement withdraws prior work within acceptance. Definition retirement closes requests without the same notice-withdrawal steps. An accepted request remains withdrawable until settlement after expiry.
