Skip to content

fix(delivery): disambiguate hook cancellations from delivery failures#1693

Open
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-57843-fix-delivery-outcome-metadata
Open

fix(delivery): disambiguate hook cancellations from delivery failures#1693
BingqingLyu wants to merge 1 commit into
mainfrom
fork-pr-57843-fix-delivery-outcome-metadata

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Enrich deliverOutboundPayloads return type from OutboundDeliveryResult[] to DeliveryOutcome — carries cancelledCount and allCancelledByHook so callers can distinguish intentional hook suppression from delivery failure
  • Wrap mid-stream non-bestEffort throws in DeliveryError with sentBeforeError to prevent blind retries that duplicate already-delivered messages
  • Update all 5 callers that use the return value; 9 fire-and-forget callers need no changes

Motivation

Closes openclaw#57766. Unblocks correct delivery status tracking in openclaw#53961 and openclaw#57755 — both currently report hook cancellations as deliveryStatus.succeeded: false.

Test plan

New tests added:

  • Hook cancels all payloads → allCancelledByHook: true, empty results, cancelledCount matches payload count
  • Hook cancels some payloads → partial cancelledCount, allCancelledByHook: false
  • Normal delivery → cancelledCount: 0, allCancelledByHook: false
  • Non-bestEffort partial send failure → DeliveryError with sentBeforeError
  • Non-bestEffort first-payload failure → original error (not DeliveryError)

🤖 Generated with Claude Code

…openclaw#57766)

Enrich deliverOutboundPayloads return type from OutboundDeliveryResult[]
to DeliveryOutcome — carries cancelledCount and allCancelledByHook so
callers can distinguish intentional hook suppression from delivery failure.

Wrap mid-stream non-bestEffort throws in DeliveryError with
sentBeforeError to prevent blind retries that duplicate already-delivered
messages. Guard retryTransientDirectCronDelivery against DeliveryError
so partial sends are never retried in the cron direct-delivery path.

DeliveryError is detected via a local isDeliveryError(err) helper that
checks err.name + Array.isArray(err.sentBeforeError), with DeliveryError
imported as a type only. This keeps the heavy outbound delivery module
off delivery-dispatch.ts's cold-startup import graph (preserving the
existing loadDeliveryOutboundRuntime boundary) and stays defensive
against a third-party adapter throwing a same-named error.

Updates all 5 callers that use the return value; 9 fire-and-forget
callers need no changes. Test mocks updated to return DeliveryOutcome
shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(delivery): deliverOutboundPayloads return type cannot distinguish hook cancellations from failures

2 participants