ee2caa0bb0
Add a game-agnostic economy service that exposes atomic, fail-closed
operations over Core's existing durable tables rather than forking a
parallel persistence stack:
* currency ledger -> clubs.coins
* owned inventory -> owned_cards
* entitlements -> packs (opaque definition_id, consume-once `opened`)
Compound operations run inside a single SQLite transaction, closing the
atomicity gap in the pool-scoped club::{spend,add}_coins helpers whose
read/modify/write spans multiple round-trips. Public ops:
balance, purchase_entitlement (debit+grant), redeem_entitlement
(consume-once + add items, all-or-nothing), sell_item (remove+credit),
grant_reward (credit).
Deliberately game-neutral: currency names, entitlement/pack ids, and
per-save item-id sequences stay in the per-game adapter that drives these
primitives. 9 unit tests cover debit/credit fail-closed rollback,
consume-once, partial-redeem rollback, and non-negative guards.