---
id: STATE-COM-FUL-006
title: Parcel and carrier label lifecycle
object: DOM-COM-FUL-004
product_area: commerce
module: fulfillment
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
states:
  - name: packed
    meaning: >-
      The parcel or live shipment contents are packed; carrier purchase intent
      is tracked separately.
  - name: labelled
    meaning: >-
      A parcel has a retained purchased label, or every live shipment parcel is
      labelled.
  - name: manifested
    meaning: Carrier preparation is closed and departure can be confirmed.
  - name: handed_to_carrier
    meaning: >-
      Carrier departure is retained with its participating stock and delivery
      effects.
  - name: in_transit
    meaning: A declared lifecycle state retained by its owning process.
  - name: delivered
    meaning: The carrier or permitted manual report records delivery.
  - name: exception
    meaning: Carrier tracking reports a shipment problem.
  - name: returned_to_sender
    meaning: Carrier tracking reports return towards the sender.
  - name: voided
    meaning: >-
      The carrier label is voided or the parcel has been removed from shipment
      work.
  - name: collected
    meaning: Pickup departure is retained with its named collector.
  - name: requested
    meaning: Purchase intent is retained before the carrier result is known.
    record: carrier_label
  - name: purchased
    meaning: 'Successful purchase retains tracking, label and cost.'
    record: carrier_label
  - name: failed
    meaning: The attempt is definitively refused or known not to have executed.
    record: carrier_label
  - name: void_failed
    meaning: Carrier void was refused and the label cost remains retained.
    record: carrier_label
transitions:
  - from: packed
    to: packed
    trigger: >-
      The owning process records another allowed update without changing this
      state.
    guard: >-
      The carrier shipment must be packed or labelled, its parcel packed and
      account active, with an accepted format.
    side_effects:
      - Store a requested carrier-label attempt while leaving the parcel packed.
    who: Warehouse staff (shipment update)
    provenance: test
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#buys
      the first label through UPS under package:<id>:1 (the intent then the
      outcome), the tracking number and the cost on the label, the package
      labelled
  - from: packed
    to: labelled
    trigger: Carrier purchase success or staff settlement retains a purchased label.
    guard: The purchase result must still find its label attempt requested.
    side_effects:
      - 'Save the purchased tracking number, label and cost.'
      - Shipment labelled once each live parcel is.
    who: Label workflow or staff resolution
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:recordPurchaseOutcome,resolveLabelPurchase
  - from: packed
    to: packed
    trigger: >-
      The owning process records another allowed update without changing this
      state.
    guard: The carrier result must establish failure rather than unknown execution.
    side_effects:
      - Mark the carrier attempt failed while retaining the packed parcel.
    who: Label workflow
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:purchaseLabelForPackage
  - from: labelled
    to: packed
    trigger: >-
      Packing, purchase refusal or successful reprint void leaves the parcel
      ready for preparation.
    guard: A purchased label must exist for the parcel.
    side_effects:
      - >-
        Retain a separately keyed void attempt and mark the label voided on
        confirmation.
    who: Warehouse staff
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:voidLabelOfPackage
  - from: labelled
    to: voided
    trigger: Carrier void succeeds or cancellation removes the parcel.
    guard: A purchased label must exist and the workflow must request parcel removal.
    side_effects:
      - >-
        A rejected void keeps the cost, marks the label void failed and raises a
        void failed stock finding.
    who: Warehouse staff or the cancellation
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:voidLabelsOfShipment
  - from: labelled
    to: manifested
    trigger: Staff close carrier preparation.
    guard: The shipment must be labelled before manifestation.
    side_effects: []
    who: Warehouse staff
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/handoff.ts:manifestShipment
  - from: manifested
    to: handed_to_carrier
    trigger: Staff confirm physical carrier departure.
    guard: 'The shared handoff must accept shipment, line and authorization checks.'
    side_effects: []
    who: Warehouse staff
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/handoff.ts:handoffShipment
  - from: handed_to_carrier
    to: in_transit
    trigger: Requested tracking.
    guard: The shipment must have departed and the carrier parcel must have tracking.
    side_effects: []
    who: Staff requesting tracking
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:trackPackage
  - from: in_transit
    to: delivered
    trigger: Explicit carrier tracking or a manual report records delivery.
    guard: The parcel must belong to a departed carrier shipment.
    side_effects:
      - Shipment delivered once each live parcel is.
    who: Staff requesting tracking
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:trackPackage
  - from: in_transit
    to: exception
    trigger: Explicit tracking records a carrier problem.
    guard: The parcel must belong to a departed carrier shipment.
    side_effects: []
    who: Staff requesting tracking
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:trackPackage
  - from: in_transit
    to: returned_to_sender
    trigger: Explicit tracking records return towards the sender.
    guard: The parcel must belong to a departed carrier shipment.
    side_effects: []
    who: Staff requesting tracking
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/labels.ts:trackPackage
  - from: packed
    to: collected
    trigger: Staff hand a packed pickup to its named collector.
    guard: Collection must use a packed pickup shipment.
    side_effects: []
    who: Administrator
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/handoff.ts:handoverShipment
  - from: packed
    to: voided
    trigger: Carrier void succeeds or cancellation removes the parcel.
    guard: Cancellation must remove every retained parcel content.
    side_effects: []
    who: The cancellation
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/fulfillment/cancellation-fence.ts:cancelFencedShipmentLines
  - from: requested
    to: purchased
    trigger: The carrier or staff-confirmed result establishes purchase.
    guard: The retained carrier-label attempt must still be requested.
    side_effects:
      - 'Store tracking, cost and label references.'
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelOutcome
  - from: requested
    to: failed
    trigger: The purchase result establishes refusal or known non-execution.
    guard: The retained carrier-label attempt must still be requested.
    side_effects:
      - Store purchase failure diagnosis.
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelOutcome
  - from: purchased
    to: voided
    trigger: The carrier confirms label void.
    guard: The retained label must be purchased or have a refused void.
    side_effects:
      - Store the successful void timestamp.
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelVoid
  - from: purchased
    to: void_failed
    trigger: The carrier refuses label void.
    guard: The retained label must be purchased or have a refused void.
    side_effects:
      - Keep purchase cost and store the void failure diagnosis.
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelVoid
  - from: void_failed
    to: voided
    trigger: The carrier confirms label void.
    guard: The retained label must be purchased or have a refused void.
    side_effects:
      - Store the successful void timestamp.
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelVoid
  - from: void_failed
    to: void_failed
    trigger: The carrier refuses label void.
    guard: The retained label must be purchased or have a refused void.
    side_effects:
      - Keep purchase cost and store the void failure diagnosis.
    who: Label workflow
    record: carrier_label
    provenance: observed
    source: >-
      services-commerce:modules/shipping/services/persistence/carrier-labels.ts:recordLabelVoid
invalid:
  - from: packed
    to: packed
    why: >-
      An outstanding carrier purchase must be settled under its existing key
      before another purchase starts.
  - from: voided
    to: labelled
    why: Removed parcels cannot be relabelled; preparation needs another parcel.
  - from: collected
    to: in_transit
    why: Pickup collection has no carrier lifecycle.
concurrency: >-
  Intent and result transactions surround the external call. Requested-state
  result checks prevent two retained outcomes for one attempt; they do not turn
  carrier calls into database work.
invariants:
  - INV-DOM-COM-FUL-004-06
  - INV-DOM-COM-FUL-004-07
evidence:
  - >-
    services-commerce at c8b66a98: modules/shipping/db/packages.table.ts,
    carrier-labels.table.ts; services/fulfillment/labels.ts;
    services/persistence/carrier-labels.ts, packages.ts;
    docs/migrations/shipping/README.md (D-P8S-08, D-P8S-15).
---

# Parcel and Carrier Label Lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> packed: packing
  packed --> packed: label attempt requested
  packed --> labelled: purchased or resolved
  packed --> packed: label attempt failed
  labelled --> packed: void to re-print
  labelled --> voided: void and pull
  packed --> voided: pulled by a cancellation
  labelled --> manifested
  manifested --> handed_to_carrier
  handed_to_carrier --> in_transit
  in_transit --> delivered
  in_transit --> exception
  in_transit --> returned_to_sender
  packed --> collected: pick-up
```

Carrier-label attempts retain their own progression while the parcel can remain packed.

```mermaid
stateDiagram-v2
  [*] --> requested
  requested --> purchased: purchase confirmed
  requested --> failed: refusal confirmed
  purchased --> voided: void confirmed
  purchased --> void_failed: void refused
  void_failed --> voided: later void confirmed
  void_failed --> void_failed: later void refused
```

## Transitions Explained

Packing creates a packed parcel. Purchasing retains a requested carrier-label attempt while the parcel stays packed; success labels it, and refusal leaves it packed. A successful void either permits another preparation or removes the parcel.

## What Cannot Happen

Uncertain purchases must be resolved under their existing key before another purchase starts. Pickup parcels refuse carrier work. Tracking can move a handed-over parcel directly to delivery or a problem state without an intermediate transit observation.

## Concurrency and Timing

Intent and outcome use separate transactions around the carrier call. No background worker settles labels or polls tracking, so another request or a staff resolution provides continuation.
