You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f684f23
Browse filesBrowse the repository at this point in the historyBrowse files
The frontend determines retryability directly from `eligible`/`reason` — it
42
-
never has to infer it from other fields.
46
+
The frontend determines retryability directly from `eligible`/`reason` — the
47
+
nver has to infer it from other fields.
43
48
44
49
### Retry submission
45
50
46
-
`POST /v1/operations/queue/:id/retry` requires:
51
+
POST /v1/operations/queue/:id/retry requires:
47
52
48
53
| Input | Where | Why |
49
54
| --- | --- | --- |
@@ -56,11 +61,86 @@ never has to infer it from other fields.
56
61
Authentication is not authorization: capability and expiry are revalidated on
57
62
every request.
58
63
64
+
## Dead-Letter Replay (PREWAVE-BE-049)
65
+
66
+
Dead-letter replay is a distinct, higher-risk surface from plain retry. It is
67
+
**denied by default** and only proceeds when every guard below is satisfied.
68
+
69
+
### Replay request shape
70
+
71
+
`POST /v1/operations/queue/:id/replay` requires:
72
+
73
+
| Input | Where | Why |
74
+
| --- | --- | --- |
75
+
|`Idempotency-Key`| header | Required. Duplicate keys replay the stored outcome; they never re-execute. A duplicate cannot produce a second effect. |
76
+
|`X-Precondition-Token`| header (or `preconditionToken` body) | Required. Must match the item's current version, or the request is rejected as stale. |
77
+
|`X-Authority-Capability`| header | Required. Must equal `OPERATIONS_REPLAY_SUBMIT` and the item's required capability. |
78
+
|`X-Authority-Expires-At`| header (ISO) | Required. Revalidated on every request; missing/expired/ambiguous fails closed. |
79
+
|`reason`| body (required) | Non-empty operator rationale, audited with the replay record. |
80
+
|`dryRun`| body (required) | When `true`, evaluates and returns the decision without enqueuing work. |
81
+
|`originalPayloadHash`| body (required) | Sha-256 hex of the original dead-letter payload. Must match the stored hash or the replay is rejected as conflict. |
82
+
|`batchLimit`| body (optional) | Bounded batch size; defaults to `1` and is capped at the configured maximum. Exceeding the cap fails closed. |
83
+
84
+
### Replay guards (fail closed)
85
+
86
+
1.**Authorization.** Requires `OPERATIONS_REPLAY_SUBMIT` capability and a
87
+
valid, non-expired authority. Missing, stale, revoked, or ambiguous authority
88
+
returns `DENIED ` or `STALE_AUTHORITY`.
89
+
2.**Reason.** A replay without a non-empty reason is rejected. The reason is
90
+
recorded in the audit record.
91
+
3.**Bounds.** confirmed duplication risk, quarantined items, and exceeding the
92
+
configured batch cap all fail closed.
93
+
4.**Dry run.**`dryRun` is required and must be explicit; it never enqueues
94
+
work and never advances the item version.
95
+
5.**Original payload hash.**`originalPayloadHash` must match the stored
96
+
dead-letter payload hash; a mismatch is `CONFLICT`.
97
+
6.**Release/schema compatibility.** Replay is prevented across release or schema
98
+
incompatibility. The item's `releaseId`, chain ID, deployment block, and
99
+
artifact checksum must match the current authoritative release; a stale or mismatched
100
+
release returns `STALE_RELEASE`.
101
+
7.**Audit record.** Every accepted or rejected replay carries a stable `auditId`.
102
+
The audit record links the original dead-letter reference to the replay
0 commit comments