Parent: #1537
Related: #1511
Priority
P1.
Problem
AI SaaS, API products, prepaid plans, promotions, and service recovery commonly require credits that can be granted, reserved, consumed, released, refunded, and expired. Croco currently has metering and invoice credit line-item concepts, but no durable account ledger. A mutable balance field would lose causality, permit silent correction, and make concurrent usage unsafe.
Desired outcome
Create @croco/credits-core, a provider-neutral append-only credit ledger whose balance is a projection of immutable transactions and whose reservation flow supports usage that is estimated before final settlement.
Scope
Core model
- Branded
CreditAccountId, CreditTransactionId, CreditReservationId, and decimal-safe CreditAmount.
- Credit accounts scoped by tenant and optional wallet/purpose key.
- Transaction kinds: grant, reserve, commit, release, expire, refund, and compensating adjustment.
- Grant lots with optional expiry, source/reference, meter restrictions, and consumption priority.
- Available, reserved, consumed, expired, and lifetime-granted projections.
- Explicit allocation records showing which grant lots funded each consumption.
- Idempotency key and immutable semantic reference on every command.
Service operations
- open account;
- grant credits;
- reserve an upper-bound amount;
- commit actual usage less than or equal to the reservation;
- release unused reservation;
- consume directly where no reservation is needed;
- refund a prior consumption through a compensating transaction;
- expire eligible grant lots in bounded batches;
- query balances and transaction history at a consistent ledger position.
Integration seams
- Optional metering reference/meter key, without replacing
metering-core.
- Domain events after successful commit.
- Problem contracts for insufficient credits, expired grants, reservation mismatch, duplicate conflict, account mismatch, invalid amount, and stale ledger position.
- In-memory store and conformance suite for persistent adapters.
Required invariants
- Transactions are immutable and append-only.
- Balance cannot be set directly.
- Amounts are positive, finite, and decimal-safe.
- Reserve/commit/release are atomic and idempotent.
- A commit cannot exceed its reservation.
- Expired/restricted grants cannot fund ineligible consumption.
- Concurrent consumption cannot overdraw available credits.
- Refund/adjustment never rewrites original history.
Acceptance criteria
Verification
- invariant/property tests;
- concurrent reserve/commit hostile tests;
- idempotency conflict matrix;
- expiry/allocation golden fixtures;
- event-after-commit tests;
- packed public API type tests.
Non-goals
- Fiat money, payment custody, or a general wallet.
- Tax, invoice, or provider rating calculation.
- Arbitrary negative balance or debt in v1.
- Cross-currency conversion.
- Promotional campaign management.
Parent: #1537
Related: #1511
Priority
P1.
Problem
AI SaaS, API products, prepaid plans, promotions, and service recovery commonly require credits that can be granted, reserved, consumed, released, refunded, and expired. Croco currently has metering and invoice credit line-item concepts, but no durable account ledger. A mutable
balancefield would lose causality, permit silent correction, and make concurrent usage unsafe.Desired outcome
Create
@croco/credits-core, a provider-neutral append-only credit ledger whose balance is a projection of immutable transactions and whose reservation flow supports usage that is estimated before final settlement.Scope
Core model
CreditAccountId,CreditTransactionId,CreditReservationId, and decimal-safeCreditAmount.Service operations
Integration seams
metering-core.Required invariants
Acceptance criteria
Verification
Non-goals