Requires money as integer minor units plus an ISO 4217 currency code, documented half-even rounding in this profile, a ban on floating-point money arithmetic, and conversion only at a named rate source.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
Monetary values are stored and transmitted as an integer count of minor units together with an ISO 4217 alphabetic currency code and a known minor exponent. Arithmetic that mixes currencies without an explicit conversion is rejected. Rounding follows half-even (banker's rounding) at the documented boundary, with cases in rounding-fixtures.yaml. Binary floating-point types are forbidden for money. Foreign-exchange conversion cites a named rate source and an as-of date. Refunds and ledger posting remain in the related payments block; this block only fixes representation and rounding.
Scope
- Invoice lines, tax, wallet balances, and in-app prices for billing.
- Persistence, API payloads, and in-process money types.
- FX conversion when a display or settlement currency differs.
Outside this block
- Payment-processor settlement files and card-scheme rounding.
- Crypto-asset denominations.
- Tax jurisdiction determination.
Contract
- Every money value has
amount_minor(integer),currency_code, andminor_exponentconsistent with that code in the profile. - Addition and comparison require equal
currency_code; otherwisemoney_currency_mismatch. - Line totals from
quantity_milliandunit_price_minorround with half-even to minor units; the worked profile total is 2998 EUR minor. - Tax uses basis points and the fixture expected cents; midpoints use half-even, not half-up.
- FX conversion records
source,as_of, pair, and resulting minor units; implicit mid-market guesses are forbidden. - Schema and serializers reject IEEE-754 money columns and implicit currency defaults.
Implementation guidance
- Use a money type with currency. Validate ISO 4217 exponents. Round once per named step.
- Split remainders using the fixture rule so parts sum to the original total.
Failure handling and safeguards
- Integer overflow fails the transaction. Missing FX for
as_ofrefuses conversion. - Displays format from minor units;
rounding-fixtures.yamlis the oracle.
Verification and operations
- Replay fixtures in CI. Sample invoices against tax_minor 630 on net 2999 at 2100 bp in this profile.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.