---
id: ATS-COM-FUL-003
scope: CAP-COM-FUL-003
product_area: commerce
module: fulfillment
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-FUL-003-01
    title: Provisional member pricing retains its delivery dependency
    level: api
    proves:
      - BR-CAP-COM-FUL-003-01
      - BR-CAP-COM-FUL-003-02
    preconditions: A buyer orders membership and a member-priced item together.
    steps: Place the order and satisfy its payment condition.
    expected: >-
      The item references the membership prerequisite and remains waiting for
      its delivery.
    negative: false
    data_needs: Fixtures for provisional member pricing retains its delivery dependency.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#writes
        the T-shirt’s obligation with the prerequisite on the membership line
        and domain_prerequisite on its gate; the membership’s without
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#opens
        the membership’s gate and keeps the T-shirt’s closed
        prerequisite_not_met while the membership is not delivered
      - TST-COM-FUL-023
    provenance: test
    source: >-
      services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#writes
      the T-shirt’s obligation with the prerequisite on the membership line and
      domain_prerequisite on its gate; the membership’s without
    category: rule
  - id: ATS-COM-FUL-003-02
    title: Membership completion settles waiting purchases once
    level: api
    proves:
      - BR-CAP-COM-FUL-003-03
    preconditions: A paid purchase depends on undelivered membership.
    steps: Complete the membership delivery.
    expected: Its prerequisite is recorded satisfied once and its gate can open.
    negative: false
    data_needs: Fixtures for membership completion settles waiting purchases once.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#delivers
        the membership, meets the T-shirt’s prerequisite with
        order.prerequisite_met on the history, and opens its gate
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#records
        the registration’s prerequisite met, writes it on the history once, and
        opens its gate (authorized, queued); a repeat finds nothing waiting
      - TST-COM-FUL-023
      - TST-COM-FUL-046
    provenance: test
    source: >-
      services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#delivers
      the membership, meets the T-shirt’s prerequisite with
      order.prerequisite_met on the history, and opens its gate
    category: transition
  - id: ATS-COM-FUL-003-03
    title: Permanent prerequisite loss requires staff attention
    level: api
    proves:
      - BR-CAP-COM-FUL-003-04
      - BR-CAP-COM-FUL-003-06
    preconditions: A paid purchase relies on the membership line.
    steps: >-
      Exercise permanent membership failure and, separately, membership
      cancellation.
    expected: >-
      The purchase retains its price and gains one failed-prerequisite block and
      exception.
    negative: true
    data_needs: Fixtures for permanent prerequisite loss requires staff attention.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#blocks
        the T-shirt prerequisite_failed when the membership fails for good, with
        the block on the history and the exception raised for staff (05 §4)
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#blocks
        the registration prerequisite_failed with the membership named in its
        facts, writes the block on the history once, and raises the exception
        once
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#a
        cancelled membership (the order cancelled a line before it enrolled)
        blocks its dependents too
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#leaves
        the T-shirt line priced as it was: nothing reprices a placed line (R-04)
      - TST-COM-FUL-023
      - TST-COM-FUL-046
    provenance: test
    source: >-
      services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#blocks
      the T-shirt prerequisite_failed when the membership fails for good, with
      the block on the history and the exception raised for staff (05 §4)
    category: failure
  - id: ATS-COM-FUL-003-04
    title: Unsettled outcomes leave dependent work alone
    level: api
    proves:
      - BR-CAP-COM-FUL-003-05
    preconditions: Several orders contain membership-dependent purchases.
    steps: Report retryable failure and work still in progress.
    expected: Those outcomes do not change any dependent obligation.
    negative: true
    data_needs: Fixtures for unsettled outcomes leave dependent work alone.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#a
        retryable failure, an obligation in flight, a line nothing depends on,
        and the dependents of another order
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#names
        what settles the dependents: a completed fulfil meets them; a permanent
        failure, a resolution or a cancellation fails them; the rest nothing
      - TST-COM-FUL-046
    provenance: test
    source: >-
      services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#a
      retryable failure, an obligation in flight, a line nothing depends on, and
      the dependents of another order
    category: edge
  - id: ATS-COM-FUL-003-05
    title: A later completed membership can release blocked work
    level: api
    proves:
      - BR-CAP-COM-FUL-003-07
    preconditions: Earlier membership failure blocked a dependent purchase.
    steps: 'Re-evaluate the blocked work, then re-authorize and complete membership.'
    expected: The block persists until successful membership delivery permits opening.
    negative: false
    data_needs: Fixtures for a later completed membership can release blocked work.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#keeps
        the registration blocked when the sweep evaluates it again, and opens it
        once the membership is re-authorized and completes (05 §4)
      - TST-COM-FUL-046
    provenance: test
    source: >-
      services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#keeps
      the registration blocked when the sweep evaluates it again, and opens it
      once the membership is re-authorized and completes (05 §4)
    category: transition
  - id: ATS-COM-FUL-003-06
    title: Membership delivery opens the dependent merchandise gate
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-FUL-002-07
      - BR-CAP-COM-FUL-003-02
      - BR-CAP-COM-FUL-003-03
      - BR-CAP-COM-FUL-004-04
    exercises:
      - CAP-COM-FUL-002
      - CAP-COM-FUL-003
      - CAP-COM-FUL-004
    relies_on:
      - ATS-COM-FUL-002-06
      - ATS-COM-FUL-003-02
      - ATS-COM-FUL-004-03
    preconditions: >-
      A paid cart contains a membership and a member-priced shirt. Both have
      waiting delivery work.
    steps: 'Evaluate payment, deliver the membership and then dispatch the shirt.'
    expected: >-
      The shirt waits before membership completion, records its satisfied
      prerequisite, then completes delivery.
    negative: false
    data_needs: >-
      An isolated workspace with the products, records, authority and quantities
      described in the preconditions.
    bound_to:
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#delivers
        the membership, meets the T-shirt’s prerequisite with
        order.prerequisite_met on the history, and opens its gate
      - TST-COM-FUL-023
    provenance: test
    source:
      - >-
        services-commerce:modules/fulfillment/tests/unit/policies/evaluate-gate.spec.js#the
        participant’s prerequisite is waited for, and a child line follows its
        parent unless the policy says not
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#delivers
        the membership, meets the T-shirt’s prerequisite with
        order.prerequisite_met on the history, and opens its gate
      - >-
        services-commerce:modules/fulfillment/tests/e2e/obligation-register.e2e.spec.js#completes
        the obligation and answers it as it stands; the repeat answers the same
  - id: ATS-COM-FUL-003-07
    title: >-
      A recovered membership releases the blocked purchase while staff retain
      the diagnosis
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-FUL-003-07
      - BR-CAP-COM-FUL-003-06
      - BR-CAP-COM-FUL-005-05
      - BR-CAP-COM-FUL-008-03
    exercises:
      - CAP-COM-FUL-003
      - CAP-COM-FUL-005
      - CAP-COM-FUL-008
    relies_on:
      - ATS-COM-FUL-003-05
      - ATS-COM-FUL-005-04
      - ATS-COM-FUL-008-03
    preconditions: >-
      Membership delivery failed permanently and its member-priced shirt is
      blocked. The failure is visible to staff.
    steps: >-
      Inspect and acknowledge the finding, re-authorize the membership, complete
      its new instruction, then inspect the shirt and retained history.
    expected: >-
      The shirt can open after membership completion; its original price remains
      visible. Acknowledgement alone does not release it.
    negative: false
    data_needs: >-
      An isolated workspace with the products, records, authority and quantities
      described in the preconditions.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#keeps
        the registration blocked when the sweep evaluates it again, and opens it
        once the membership is re-authorized and completes (05 §4)
      - >-
        services-commerce:modules/fulfillment/tests/e2e/obligation-register.e2e.spec.js#overrides
        the gate of the unpaid obligation, authorizing it regardless of the
        facts, with the override on the obligation
      - >-
        services-commerce:modules/operations/tests/e2e/operations.e2e.spec.js#acknowledges
        then resolves the finding, with the interventions logged, the order’s
        history and the audit events recorded
evidence:
  - repository: services-commerce
    tests:
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#writes
        the T-shirt’s obligation with the prerequisite on the membership line
        and domain_prerequisite on its gate; the membership’s without
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#opens
        the membership’s gate and keeps the T-shirt’s closed
        prerequisite_not_met while the membership is not delivered
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#delivers
        the membership, meets the T-shirt’s prerequisite with
        order.prerequisite_met on the history, and opens its gate
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#records
        the registration’s prerequisite met, writes it on the history once, and
        opens its gate (authorized, queued); a repeat finds nothing waiting
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#blocks
        the T-shirt prerequisite_failed when the membership fails for good, with
        the block on the history and the exception raised for staff (05 §4)
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#blocks
        the registration prerequisite_failed with the membership named in its
        facts, writes the block on the history once, and raises the exception
        once
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#a
        cancelled membership (the order cancelled a line before it enrolled)
        blocks its dependents too
      - >-
        services-commerce:modules/fulfillment/tests/e2e/same-cart-grants.e2e.spec.js#leaves
        the T-shirt line priced as it was: nothing reprices a placed line (R-04)
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#a
        retryable failure, an obligation in flight, a line nothing depends on,
        and the dependents of another order
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#names
        what settles the dependents: a completed fulfil meets them; a permanent
        failure, a resolution or a cancellation fails them; the rest nothing
      - >-
        services-commerce:modules/fulfillment/tests/integration/services/register/prerequisite-settlement.integration.spec.js#keeps
        the registration blocked when the sweep evaluates it again, and opens it
        once the membership is re-authorized and completes (05 §4)
coverage:
  rule: covered
  transition: covered
  validation: 'gap: FND-COM-FUL-058'
  permission: 'gap: FND-COM-FUL-058'
  edge: covered
  failure: covered
  boundary: 'gap: FND-COM-FUL-058'
  concurrency: 'gap: FND-COM-FUL-058'
  invariant: 'gap: FND-COM-FUL-058'
  interaction: covered
coverage_notes:
  validation: >-
    No scenario specifically isolates this dimension; the coverage finding
    retains the missing proof.
  permission: >-
    No scenario specifically isolates this dimension; the coverage finding
    retains the missing proof.
  boundary: >-
    No scenario specifically isolates this dimension; the coverage finding
    retains the missing proof.
  concurrency: >-
    No scenario specifically isolates this dimension; the coverage finding
    retains the missing proof.
  invariant: >-
    No scenario specifically isolates this dimension; the coverage finding
    retains the missing proof.
transition_audit:
  - model: STATE-COM-FUL-001
    from: pending
    to: eligible
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:openGate
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: blocked
    to: eligible
    source: 'services-commerce:modules/fulfillment/services/register/gate-evaluation.ts'
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: eligible
    to: authorized
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:openGate
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: pending
    to: blocked
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:recordGateEvaluation,placeStaffHold
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: pending
    to: cancelled
    source: 'services-commerce:docs/migrations/obligation-register/README.md#D-P4-03'
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: blocked
    to: cancelled
    source: 'services-commerce:docs/migrations/obligation-register/README.md#D-P4-03'
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: eligible
    to: cancelled
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:OBLIGATION_TRANSITIONS
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: authorized
    to: in_progress
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:recordObligationOutcome
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: authorized
    to: completed
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:recordObligationOutcome,completeObligationManually
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: in_progress
    to: completed
    source: >-
      services-commerce:modules/shipping/tests/integration/services/fulfillment/shipping-flow.integration.spec.js#completes
      every unit’s obligation through the register (the allocation as the
      record), and emits one deferred cost relief fact per item
    coverage: covered
    scenarios:
      - ATS-COM-FUL-004-12
      - ATS-COM-FUL-012-10
      - ATS-COM-FUL-013-10
      - ATS-COM-FUL-014-01
      - ATS-COM-FUL-014-06
      - ATS-COM-FUL-014-07
      - ATS-COM-FUL-018-08
  - model: STATE-COM-FUL-001
    from: authorized
    to: failed
    source: >-
      services-commerce:modules/fulfillment/tests/integration/services/register/obligation-worker.integration.spec.js#fails
      the obligation with the participant’s code, raises obligation_failed, and
      acknowledges the item
    coverage: covered
    scenarios:
      - ATS-COM-FUL-004-04
  - model: STATE-COM-FUL-001
    from: in_progress
    to: failed
    source: >-
      services-commerce:modules/fulfillment/services/register/register-sweeper.ts:sweepRegister
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: failed
    to: authorized
    source: >-
      services-commerce:modules/fulfillment/tests/e2e/obligation-register.e2e.spec.js#re-authorizes
      the failed obligation at sequence two, which the participant fails again,
      then resolves it with its exceptions
    coverage: covered
    scenarios:
      - ATS-COM-FUL-005-04
  - model: STATE-COM-FUL-001
    from: failed
    to: resolved
    source: >-
      services-commerce:modules/fulfillment/services/register/obligation-interventions.ts:resolveObligationByStaff
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
  - model: STATE-COM-FUL-001
    from: completed
    to: superseded
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:OBLIGATION_TRANSITIONS
    coverage: 'gap: FND-COM-FUL-058'
    scenarios: []
permission_audit:
  - key: commerce.obligations.read
    where_checked: api
    coverage: 'gap: FND-COM-FUL-058'
    note: >-
      Per-key positive and negative coverage is not separately mapped;
      permission scenarios retain the observed aggregate tests.
related_audit:
  - capability: CAP-COM-FUL-005
    scenarios:
      - ATS-COM-FUL-003-07
  - capability: CAP-COM-FUL-008
    scenarios:
      - ATS-COM-FUL-003-07
invariant_audit:
  - invariant: INV-DOM-COM-FUL-001-01
    scenarios:
      - ATS-COM-FUL-004-07
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/obligations.table.ts:obligations_subject_uq
  - invariant: INV-DOM-COM-FUL-001-02
    scenarios:
      - ATS-COM-FUL-004-07
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:OBLIGATION_TRANSITIONS;
      db/migrations/20261018004016_obligation_register.sql:refuse_obligation_regression
  - invariant: INV-DOM-COM-FUL-001-03
    scenarios:
      - ATS-COM-FUL-004-07
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/obligations.table.ts:obligations_authorization_state_check
  - invariant: INV-DOM-COM-FUL-001-04
    scenarios:
      - ATS-COM-FUL-004-03
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/obligations.table.ts:obligations_quantity_check
  - invariant: INV-DOM-COM-FUL-001-05
    scenarios:
      - ATS-COM-FUL-002-08
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:openGate
  - invariant: INV-DOM-COM-FUL-001-06
    scenarios:
      - ATS-COM-FUL-004-02
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/services/persistence/obligations.ts:recordObligationOutcome
  - invariant: INV-DOM-COM-FUL-001-07
    scenarios:
      - ATS-COM-FUL-005-02
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/obligation-attempts.table.ts;
      modules/fulfillment/db/intervention-logs.table.ts (UPDATE, DELETE and
      TRUNCATE revoked)
  - invariant: INV-DOM-COM-FUL-001-08
    scenarios:
      - ATS-COM-FUL-005-02
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/services/register/obligation-interventions.ts
  - invariant: INV-DOM-COM-FUL-001-09
    scenarios:
      - ATS-COM-FUL-005-03
    coverage: covered
    provenance: test
    source: >-
      services-commerce:docs/migrations/obligation-register/README.md#D-P4-16
      (obligation-register.e2e five simultaneous approvals)
  - invariant: INV-DOM-COM-FUL-001-10
    scenarios:
      - ATS-COM-FUL-006-03
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/enforcements.table.ts:enforcements_cause_uq
  - invariant: INV-DOM-COM-FUL-001-11
    scenarios:
      - ATS-COM-FUL-002-07
    coverage: covered
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/services/facts/financial-facts-handler.ts
  - invariant: INV-DOM-COM-FUL-001-12
    scenarios: []
    coverage: 'gap: FND-COM-FUL-058'
    provenance: observed
    source: >-
      services-commerce:modules/fulfillment/db/obligations.table.ts (composite
      RESTRICT keys)
---

# Protect a member-priced purchase until its membership arrives: Capability Test Specification

## Coverage

The category map distinguishes available cases from missing proof. A covered category has a scenario; the lifecycle and permission audits retain gaps in exhaustive coverage. Proposed cases describe the intended verification and carry no execution result.

| Rule | Scenarios |
|---|---|
| `BR-CAP-COM-FUL-003-01` | `ATS-COM-FUL-003-01` |
| `BR-CAP-COM-FUL-003-02` | `ATS-COM-FUL-003-01` |
| `BR-CAP-COM-FUL-003-03` | `ATS-COM-FUL-003-02`, `ATS-COM-FUL-003-06` |
| `BR-CAP-COM-FUL-003-04` | `ATS-COM-FUL-003-03` |
| `BR-CAP-COM-FUL-003-05` | `ATS-COM-FUL-003-04` |
| `BR-CAP-COM-FUL-003-06` | `ATS-COM-FUL-003-03` |
| `BR-CAP-COM-FUL-003-07` | `ATS-COM-FUL-003-05`, `ATS-COM-FUL-003-07` |

## Interactions With Related Capabilities

The interaction cases exercise understand and intervene in an order's delivery; review and resolve operations findings. They vary the upstream record or outcome and inspect the resulting work across the capability boundary. Workflow crossings also include stock, financial or application records when the flow depends on them. Existing test bindings retain their source anchors so a reviewer can distinguish supporting assertions from a complete workflow run.
