---
type: Axis
title: idempotency (duplicate-handling axis)
description: The idempotency/duplicate-handling architecture axis — how an operation behaves under retry/redelivery (none → idempotency-key → exactly-once). A system-singleton axis whose commitment surface is the interface/wire contract (the operation's at-least/at-most-once guarantee). DEEP (RFC #75 5A.5 / P1 #851); worked example is the post_turn / replay_pending offline-queue replay path.
tags: [axis, architecture, idempotency, retry, exactly-once, dedup, rfc-75, deep]
timestamp: 2026-06-20T00:00:00Z
---

# Idempotency (duplicate-handling axis)

> **DEEP axis (P1 #851).** Full §6 depth with a worked example from the skill's
> own history — the offline-queue / `replay_pending` redelivery path and the
> `post_turn` recording contract. Distinct from `recovery` (how a *failed*
> operation is retried) and `consistency` (how concurrent writes reconcile):
> idempotency is what happens when the *same* operation arrives *more than once*.

## Concept

Idempotency is the **duplicate-handling** axis (RFC #75 §3): how an operation
behaves when it is delivered or retried more than once. The ladder runs none
(at-least-once with duplicate effects; a retry double-applies) → idempotency-key
(the caller supplies a dedup key; a redelivery with the same key is a no-op that
returns the prior result) → exactly-once (the system guarantees a single effect
end-to-end via a dedup store + transactional outbox/inbox). Its **commitment
surface is the interface/wire contract** (§4): the guarantee is part of the
operation's contract — callers and the recovery layer build retry behavior on
top of it, and weakening it later breaks every retrying caller. Its **scope is
system-singleton** (§5): the duplicate-handling stance is a system-wide property
of how operations are processed, chosen once.

## Why it is an axis (discriminator test — §2)

1. **Ordered tiers** — each rung adds a stronger duplicate-suppression
   guarantee (none ⊂ keyed ⊂ exactly-once).
2. **Cross-cutting bundle** — a rung dictates the wire contract (a key field),
   a dedup store, the write-path's check-then-apply transaction, the
   retry/replay layer's assumptions, and the duplicate-injection tests.
3. **Asymmetric migration cost** — adding idempotency means threading a key
   through every caller and standing up a dedup store; removing it silently
   breaks callers that *relied* on safe retries (double charges, double posts).
4. **Requirement-keyed selection** — falsifiable probes (below) pick the rung.

## Tiers (the ladder)

| Tier | Adds | Commitment surface | Forecloses next-cost |
|---|---|---|---|
| `none` | nothing | interface-wire-contract | trivial → accept a key |
| `idempotency-key` | caller-supplied dedup key | interface-wire-contract | low; key store is best-effort |
| `exactly-once` | end-to-end single effect | durable-runtime-state | high; transactional dedup everywhere |

## Schema view (the §6 entry — validated by `axis_catalog`)

```yaml
id: idempotency
kind: architecture-axis
scope: system-singleton
selection:
  probes:
    - "Is double-applying this operation harmless (a pure read, a set-to-value)? → none may be fine."
    - "Could a retry double-apply a side effect (a post, a charge, a counter increment)? → at least idempotency-key."
    - "Will an unreliable transport (offline queue, network retry) redeliver operations? → idempotency-key."
    - "Must a single logical effect be GUARANTEED across crashes mid-apply? → exactly-once."
    - "Does a caller already retry on timeout assuming safety? → the contract owes it idempotency-key."
composes_with:
  - "reliable delivery = idempotency × recovery (retry is safe only if idempotent)"
  - "safe replay = idempotency × distribution (redelivery across hosts dedups)"
applies_when: []
tiers:
  - tier: none
    commitment_delta:
      surface: interface-wire-contract
      delta: "at-least-once with duplicate effects; a retry or redelivery applies the operation again. The caller owns dedup, if any."
    admin_tool: "none."
    enforcement:
      - "the operation makes no dedup promise; callers must not retry side-effecting calls."
    tests:
      - "applying the operation twice produces two effects (the contract is honest about it)."
    forecloses: "safe automatic retry of side-effecting operations."
    migration_cost_to_next: "low — accept an idempotency key + a dedup lookup before apply."
  - tier: idempotency-key
    commitment_delta:
      surface: interface-wire-contract
      delta: "the caller supplies a dedup key; a redelivery with the same key is a no-op that returns the first result. Best-effort store (a key may expire)."
    admin_tool: "dedup-key store inspector; key-TTL config."
    enforcement:
      - "the write path checks the key store before applying and records the key + result on success."
    tests:
      - "two calls with the same key apply the effect once and return the same result; different keys both apply."
    forecloses: "callers omitting the key (they lose the guarantee); unbounded key retention."
    migration_cost_to_next: "high — make the dedup + apply transactional for an end-to-end exactly-once guarantee."
  - tier: exactly-once
    commitment_delta:
      surface: durable-runtime-state
      delta: "a single logical effect is guaranteed end-to-end via a transactional dedup store (inbox/outbox): the dedup check and the effect commit atomically, surviving a crash mid-apply."
    admin_tool: "outbox/inbox monitor; stuck-message + replay console."
    enforcement:
      - "the dedup record and the side effect commit in one transaction; partial application is impossible."
    tests:
      - "a crash injected between dedup and effect leaves NEITHER or BOTH; replay never double-applies."
    forecloses: "non-transactional fast paths; the dedup store is now on the critical path."
    migration_cost_to_next: "n/a — top of the ladder."
examples:
  - "The skill's own climb: the offline-queue / `replay_pending` path replays operations recorded while a backend was unreachable. At none, a replay double-records a turn; the recording contract sits at idempotency-key in spirit — a turn carries a stable identity so a redelivery is deduped rather than creating a duplicate issue/comment. The canonical_db_dispatch + create_issue silent-milestone-drop episodes (#769/#822) are duplicate-and-loss hazards the same dedup discipline guards. Full exactly-once (transactional inbox) is above where the skill sits — replay is at-least-once-with-keyed-dedup."
```

## Selection procedure (§8)

Bidirectional check for the whole system. The escalation pass asks "does an
unreliable transport redeliver, and is the effect side-effecting?" — a yes forces
idempotency-key. The de-escalation pass asks "is double-applying provably
harmless?" Recorded in the system record; a retrying caller built on a `none`
operation is a systems-analysis finding (the retry is unsafe). 

## Composition (§5)

Idempotency is half of two **products** (derived, not authored here): reliable
delivery = **idempotency × recovery** (a retry is only safe when the target is
idempotent — recovery's retry rung *requires* at least idempotency-key); safe
replay = **idempotency × distribution** (a redelivery across hosts must dedup
against a shared store). The interaction table derives these (5A.3).
