Appearance
ResetCreditsManager
Manages reset credits and challenge reset operations with lazy credit activation.
Purpose
ResetCreditsManager handles the lifecycle of reset credits, which allow users to restart their trading challenge. Credits can come from renewals (1 pending credit per renewal), trade fund grants (unlimited), or direct payment.
Pending credits have an effectiveAfter timestamp and are lazily converted to active credits when the subscription is read. This avoids the need for background jobs or alarms to process credit activation. The manager also orchestrates the full reset flow: validating the reset method, decrementing credits, recording reset history, and restarting the challenge.
Reset credits of -1 (UNLIMITED_RESET_CREDITS) indicate unlimited free resets, granted to trade fund users.
Edge Cases & Error Handling
- Each challenge can only be reset once (new challenge gets new ID)
- Idempotency check must come first because after reset, the account changes and the challenge belongs to the old account
- Failed challenge restart rolls back credit decrement and deletes reset history record
- Unlimited credits (
-1) are never decremented convertPendingCredits()mutates the subscription object in-place to keep callers in sync without re-fetching