feat(iios): idempotency-command ledger + IdempotencyService (P9)

Adds the doc-mandated IiosIdempotencyCommand table + a reusable
IdempotencyService.run() that writes IN_FLIGHT at command start, replays the
cached response on a same-key/same-body retry, rejects a same-key/different-body
reuse (409), and retries a FAILED command. Tenant-scoped via
@@unique([scopeId, commandName, idempotencyKey]) (KG-02/KG-06).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-03 02:19:03 +05:30
parent dbf8f814c0
commit b8b7e0d3e8
7 changed files with 231 additions and 1 deletions
@@ -492,6 +492,26 @@ model IiosProcessedEvent {
@@id([consumerName, eventId])
}
/// Idempotent-command ledger (P9). Suppresses duplicate externally-visible mutations:
/// same (scope, command, key) replays the cached response; a different request → conflict.
model IiosIdempotencyCommand {
id String @id @default(cuid())
scopeId String?
commandName String
idempotencyKey String
schemaVersion String @default("v1")
actorRefId String?
requestHash String
responseHash String?
response Json?
status String @default("IN_FLIGHT") // IN_FLIGHT | COMPLETED | FAILED
createdAt DateTime @default(now())
completedAt DateTime?
@@unique([scopeId, commandName, idempotencyKey])
@@index([scopeId, status])
}
// ─── P2: messaging — receipts & unread ────────────────────────────
/// Delivery/read receipt for a message interaction, per actor.