Defines idempotent mutation semantics using a caller-scoped key, canonical request fingerprint, durable outcome state, concurrency control, expiry, and safe replay of both success and terminal failure.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Require an idempotency key for retry-prone create or side-effecting commands. Atomically claim (caller scope, operation, key), bind it to one canonical request, and replay the stored protocol outcome without repeating side effects.
Scope
- Key scope, request fingerprint, claim states, concurrent requests, stored outcomes, retries, expiry, downstream side effects, and observability.
- HTTP or message commands where clients may retry after uncertain completion.
- A deterministic contract for identical and mismatched reuse.
Outside this block
- Making naturally read-only operations stateful.
- Exactly-once delivery across arbitrary systems without idempotent consumers.
Contract
- Keys are opaque caller-generated values with length limits and are scoped by authenticated caller or tenant plus operation name.
- The first request stores a canonical fingerprint of all semantics-changing fields; reused keys with a different fingerprint return a conflict.
- A durable record has processing, succeeded, and terminal-failed states; concurrent owners cannot both execute.
- A completed replay returns the same status class and stable resource identity, while volatile headers may be regenerated.
- Retryable infrastructure failure is distinguished from a terminal domain response.
- The retention window is longer than the maximum documented client and transport retry horizon.
Implementation guidance
- Create the idempotency record and domain mutation in one transaction where possible, or coordinate with an outbox and downstream deduplication key.
- Canonicalize from validated semantic input rather than raw JSON byte order.
- Use a lease and owner token for recoverable processing records; takeover requires evidence the owner expired.
- Propagate the command identity to payments, messages, and events so downstream retries remain correlated.
Failure handling and safeguards
- A mismatched fingerprint never executes and returns a stable
idempotency_conflictcode. - An active owner returns a bounded in-progress response or waits within the request deadline.
- An expired key may execute as new only after the public retry contract says clients must no longer replay it.
Verification and operations
- Measure key use, replays, fingerprint conflicts, concurrent waits, stuck processing, outcome age, and duplicate downstream effects.
- Alert on expired leases and operations that mutate without completing their idempotency record.
- Test process death before mutation, after mutation, after outbox write, and before response delivery.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.