replayDLQ (lib/jobs/dlq.ts) enqueues a replay as a fresh job_event + job_queue pair and calls jobQueueRepository.create unguarded. Replaying the SAME dead-lettered row twice derives the SAME key — {original}:replay:{dlqId}, by design, so a double-click cannot double-deliver — so the second insert hits the job_queue_job_idempotency_key partial unique index and Prisma raises P2002, which propagates out of the Server Action behind the operator dashboard's Replay button.
Until MOTIR-3418 there were two arms. email.send reached the VENDOR arm in every unit test, where the second re-emit was swallowed server-side by an expiring dedup window and the operator saw two success toasts. The engine arm has behaved this way for every routed job since MOTIR-3463, and the engine arm is the only arm since MOTIR-3418 — so this is a production behaviour today, not a regression the retirement introduced.
dispatchEventToEngine treats exactly this violation as "already enqueued": isUniqueViolation(err) → retry once, then report it in alreadyEnqueued. That is the contract the engine states for a duplicate enqueue everywhere else. The replay path does not apply it — not by decision, but because the arm was written for the case where the row had not already been replayed.
The dedup itself is correct and wanted. The re-shape to {original}:replay:{dlqId} is deliberate (PRODECT_FINDINGS #40) and the index is what makes it enforceable. Nothing here argues for weakening either.
tests/jobs/dlq.test.ts → "replaying the SAME row twice REFUSES the second" asserts the current behaviour with the reasoning in a comment, so the defect is pinned rather than latent. Its assertion is the thing to invert when this is fixed.
replayDLQ of an already-replayed row does not throw. It resolves, having enqueued nothing new, and the caller can tell that from the return value rather than from a log line.replayedAt is not re-stamped by the no-op.tests/jobs/dlq.test.ts's double-click test asserts the new behaviour, and its comment naming this bug is removed.{original}:replay:{dlqId} re-shape are unchanged — this card weakens neither.lib/jobs/dlq.ts — replayDLQ, the unguarded jobQueueRepository.createlib/jobs/engine/dispatcher.ts — isUniqueViolation and the alreadyEnqueued contract this should matchlib/services/jobsDashboardService.ts — the Replay caller whose error surface this reachesprisma/migrations/20260825220000_job_queue_idempotency_key/migration.sql — the index