Versioned Idempotency Across Canonicalization Rollouts
Preserve mutation idempotency across request-schema and canonicalization changes by using trusted contract versions, explicit semantic mappings, safe legacy-record handling, and immutable compatible replay.
Versioned Idempotency Across Canonicalization Rollouts
Trigger
Use when an idempotent mutation changes its request schema, defaults, parser, or canonicalization while older records or clients may still retry.
Practical steps
- Keep one durable unique identity over caller, stable operation family, and idempotency key across API and fingerprint versions.
- Select the request contract from a trusted protocol boundary such as a versioned route or negotiated media type. Strictly reject unknown or nonrepresentable fields; never let a caller-controlled body label choose a weaker parser.
- Atomically store the effect with the trusted request contract, fingerprint-scheme version, digest, outcome-schema version, and immutable replay facts. The fingerprint version defines parsing, defaults, semantic projection, canonical encoding, hash domain, and algorithm.
- On retry, decode under the trusted incoming contract but compare against the existing record's fingerprint semantics. Cross versions only through an explicit lossless mapping that preserves every effect-relevant distinction. Compatible directions must implement the same semantic equivalence relation.
- Reject ambiguity. Never ignore a newly introduced field, accept whichever of several hashes happens to match, or derive an old record's replacement digest from the retry being checked.
- Before new-version writes begin, atomically tag legacy rows with their known generating scheme. If the scheme or original intent cannot be established, reject cross-version matching for that row.
- Let datastore uniqueness serialize old-client and new-client requests racing on one key. The winner's stored scheme becomes the comparison target; the loser replays only after proving equivalent intent.
- Render the requested response version from immutable stored outcome facts. If no safe adapter exists, return a compatibility error without repeating the effect or reading mutable current state.
- Deploy version-aware readers before new writers and retain old comparators, mappings, and response adapters for the full retry and rollback horizon.
- For optional publication work, distinguish failure before submission from failure after submission. A pre-submit crash can leave publication denied while the primary task continues. A post-submit crash is ambiguous and requires a server-side authorization gate plus recoverable idempotent operation status. Bound diagnostics with a finite denial-reason enum, one persistent warning per task and reason, and a fixed per-task cap.
Limits
If a legacy fingerprint erased an effect-relevant distinction and trusted original intent is unavailable, equality cannot be proven; reject the retry. Effects outside the atomic transaction require downstream idempotency or a transactional outbox with consumer deduplication. Storing canonical semantic bytes beside the digest is useful audit hardening but does not replace strict versioned comparison.
Failure prevented
This prevents duplicate effects after a lost response, changed requests matching old keys through weaker canonicalization, unsafe reuse of ambiguous legacy records, and mixed-version races producing separate effects. It also prevents uncertain auxiliary-worker completion from being mistaken for either authorization or confirmed nonpublication.
Evidence
Support is reasoned analysis from the cited conversation, including an independent reasoning review. No tests were executed.