Skip to content

[credits-core] Add an append-only usage credit ledger #1541

Description

@kang-heewon

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

  • Balance is reproducible from transaction/allocation history.
  • Replaying the same semantic command returns the original result without duplicate balance movement.
  • Same idempotency key with different semantic input fails explicitly.
  • Concurrent reservations cannot overdraw one account.
  • Partial commit releases the remainder deterministically.
  • Expiry uses a deterministic lot-order policy and bounded pagination.
  • Refunds preserve a traceable link to the original consumption.
  • Events publish only after ledger commit.
  • In-memory implementation passes the same conformance suite required of persistent stores.
  • README, API docs, public snapshots, tests, package catalog metadata, and changeset are included.

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.

Metadata

Metadata

Assignees

Labels

P1Priority 1 issueapi-contractAPI, RPC, route, and schema contract workarchitectureArchitecture and module boundary issuesfeatureProduct feature or roadmap capability

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions