---
id: TST-COM-ORD-030
title: The idempotency ledger on the mutation routes
kind: api-lifecycle
product_area: commerce
module: orders
revision: 1
status: draft
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
repository: services-commerce
files:
  - modules/checkout/tests/e2e/idempotency.e2e.spec.js
implements:
  - ATS-COM-ORD-005-01
  - ATS-COM-ORD-005-02
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 2
isolation: The suite creates its own test workspace records and removes them using the fixture cleanup.
evidence:
  - provenance: test
    source: 'services-commerce:modules/checkout/tests/e2e/idempotency.e2e.spec.js'
    test_cases:
      - >-
        answers the stored status and body, marked Idempotent-Replayed, and runs the placement once: one order
        row
      - >-
        keeps the completed claim in the ledger under the caller’s principal, the route’s operation and the
        key, with the answer’s status
      - 'is told the request is in progress, 409 request_in_progress with Retry-After: 2, and places nothing'
      - 'places the order once the claim is gone (the lease passed, or the first request released it)'
      - >-
        voids the order once, refuses the reused key with another body 409 idempotency_key_reused, and replays
        the same body
      - >-
        releases the claim of a request the route refused, so the same key runs the handler again rather than
        replaying the refusal
      - >-
        refuses a required route without an Idempotency-Key, 400 idempotency_key_required, before the handler
        runs
scenario_coverage:
  - scenario: ATS-COM-ORD-005-01
    test_cases:
      - >-
        refuses a required route without an Idempotency-Key, 400 idempotency_key_required, before the handler
        runs
      - >-
        answers the stored status and body, marked Idempotent-Replayed, and runs the placement once: one order
        row
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
  - scenario: ATS-COM-ORD-005-02
    test_cases:
      - 'is told the request is in progress, 409 request_in_progress with Retry-After: 2, and places nothing'
    scope: >-
      The cited cases exercise the scenario’s listed fixture outcomes; this register makes no verified
      conformance claim.
dependency_evidence:
  provenance: test
  source: 'services-commerce:modules/checkout/tests/e2e/idempotency.e2e.spec.js'
  declared_by_test: >-
    the composed handler with the ledger, the routes (placement, the staff void), the workflows, the stub
    participant, the persistence services and PostgreSQL (`commerce.idempotency_keys`, migration
    `20261018103615`). Doubled: the signing key pair and the other services' tables (local stand-ins); the
    claim held "by a request still running" is made through the library's own claim, as the dispatcher makes
    it, because the in-process handler answers too quickly to race against.
---

# The idempotency ledger on the mutation routes

## Verification Boundary

The suite drives the composed local API dispatcher and its registered routes.

## What This Suite Proves

The registered cases check the idempotency ledger on the mutation routes with their fixture records and assertions. Scenario bindings name only the examples those cases exercise.

## What It Does Not Prove

A registered file supplies no run result or verified conformance by itself. Local fixtures do not establish deployed cross-service behavior or complete browser journeys.

## Real Dependencies and Test Doubles

PostgreSQL and the exercised Commerce persistence or workflow code are real. Remote service records, clocks and transports follow the suite’s fixtures.

## Must Not Be Doubled

The database constraints, role restrictions, locks and transactions exercised by this suite must use PostgreSQL.
