REQ-C-007: Mutating Commands Accept --idempotency-key
Tier: Command Contract | Priority: P1
Source: §12 Idempotency & Safe Retries
Addresses: Severity: Critical / Token Spend: High / Time: High / Context: Medium
Description
Every command with danger_level: "mutating" or "destructive" MUST accept an --idempotency-key <string> argument. The command MUST use this key to detect and short-circuit duplicate invocations, returning the original result with effect: "noop" and the original response data. When no key is supplied, the framework MAY auto-generate one (deterministic, based on command + args + session) or MUST document that the operation is not deduplication-safe.
Acceptance Criteria
- Invoking a mutating command twice with the same
--idempotency-keyreturnseffect: "noop"on the second call - The second call's response
datamatches the first call's responsedata - An auto-generated idempotency key is deterministic for the same command arguments within a session
Schema
Types: manifest-response.md · response-envelope.md
The --idempotency-key flag appears in the schema for all mutating and destructive commands.
{
"flags": {
"idempotency-key": {
"type": "string",
"required": false,
"description": "Caller-supplied key; duplicate calls with the same key return the original result without re-executing"
}
}
}
Wire Format
First call:
$ tool create-order --amount 100 --idempotency-key order-abc123
{
"ok": true,
"data": { "effect": "created", "id": 42, "amount": 100 },
"error": null,
"warnings": [],
"meta": { "duration_ms": 91 }
}
Second call with the same key:
$ tool create-order --amount 100 --idempotency-key order-abc123
{
"ok": true,
"data": { "effect": "noop", "id": 42, "amount": 100 },
"error": null,
"warnings": [],
"meta": { "duration_ms": 9, "idempotency_hit": true }
}
Example
A mutating command stores the result keyed by the idempotency key and returns it on subsequent calls without re-executing.
register command "create-order":
danger_level: mutating
exit_codes:
SUCCESS (0): description: "Order created or already existed", retryable: false, side_effects: complete
ARG_ERROR(3): description: "Invalid amount", retryable: true, side_effects: none
execute(args):
cached = idempotency_store.get(args.idempotency_key)
if cached:
return response(effect="noop", **cached, meta={idempotency_hit: True})
order = create_order(amount=args.amount)
idempotency_store.set(args.idempotency_key, {id: order.id, amount: order.amount})
return response(effect="created", id=order.id, amount=order.amount)
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-C-002 | C | Provides: danger_level: mutating/destructive triggers --idempotency-key requirement |
| REQ-C-003 | C | Composes: effect: "noop" is the canonical response value for an idempotency-key hit |
| REQ-F-004 | F | Wraps: idempotency response uses ResponseEnvelope |
| REQ-C-001 | C | Composes: SUCCESS (0) covers both the live execution and the noop case |