Pre-existing (not introduced by the develop→main release; surfaced during the release audit of PR #11).
In TransferService.transfer, the idempotency path is check-then-act: findByDedupKey → if null, proceed to insertTxn. Two concurrent requests carrying the same Idempotency-Key (same source account) can both read null and both proceed; the second insert violates the client_dedup_key UNIQUE constraint and the request fails with a 500 instead of replaying the first transaction's response.
Not a money-safety issue — the UNIQUE constraint prevents the double-insert, so there's no double-spend; the loser just gets an error rather than the idempotent replay it asked for. Severity low (rare: requires truly simultaneous retries).
Fix options: catch the duplicate-key DataIntegrityViolationException on insert and re-run findByDedupKey → replayIdempotent (treat the constraint violation as "someone else won the race, replay theirs"); or take a short advisory lock keyed on the dedup hash around the check-insert. The catch-and-replay approach is smaller and matches the existing replay semantics.
Out of scope for the current release PR — the F2 idempotency-scoping commit only changed what the key is derived from, not the concurrency model.