- M6: RevertGiftCardFunding no longer silently drops unreclaimable money. A
partially-spent create/top-up claws back everything still on the card/balance
(GREATEST(0, ...) clamp instead of the old guarded 0-row block), inserts a
CRITICAL admin notification, and returns errClawbackPartiallyReversed so every
caller (till handler, stale-pending sweep, webhook) surfaces the residual
without forking the money logic; balance comparisons use pence (penceLess).
- M7: the £5,000/day admin gift-card value cap (create/top-up/transfer) is now
serialized per-admin under a bounded advisory try-lock
(acquireGiftCardDailyCapLock) so two concurrent operations cannot both read
the day's value before either writes and over-issue value.
- M4/M3: every gift-card expiry comparison now reads the DATABASE clock
(giftCardExpired -> SELECT NOW()), the same clock that wrote expiry_date, so
app-clock drift can neither extend nor shorten card life; applied on redeem,
cancellation assessment, cancel-for-user and the reversal re-verification.
- C6 consent fields carried on BuyGiftCardRequest and enforced on the
(now unreachable) 2FA fallback audit path; fallback audit row captures the
versioned consent.