Some checks failed
stamp_service.add_stamp checks card.last_stamp_at + cooldown_minutes before crediting and raises StampCooldownException if too soon. The parallel points_service.earn_points writes card.last_points_at but never reads it for enforcement — so cooldown_minutes was silently ignored for points-based programs. Mirror the stamps check in points_service.earn_points: after acquiring the row lock, compare now vs last_points_at + cooldown_minutes and raise the new PointsCooldownException if the cashier is inside the window. Add PointsCooldownException alongside StampCooldownException in exceptions.py with parity wording / error code POINTS_COOLDOWN. Surfaced during Test 3 step 3.6 — repeated earn-points calls for the same card kept crediting the customer with no rate limit even though the program's cooldown_minutes was set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>