# Pathrule Pattern: Multi-Currency Payments (1.0.0)
# ::pathrule:package:multi-currency-payments

### [RULE] Every amount carries its currency and unit contract  (path: /src/money)
<!-- scope: folder | priority: high | strict -->

A bare number is not money. Represent every amount with its currency and a documented unit contract, and never infer currency from account, locale, route, or a neighboring field. Currency exponents differ and some operations require provider-specific constraints, so one universal divide-by-100 helper is unsafe.

- Centralize currency metadata, accepted precision, formatting, comparison, allocation, and rounding behavior.
- Reject arithmetic, equality, aggregation, or persistence that mixes currencies without an explicit conversion operation.
- Parse machine amounts independently from localized display strings and never round through binary floating point.
- Allocate remainders deterministically and retain which line received each smallest unit.

Verification: Test zero-decimal and multi-decimal currencies, negative adjustments, large values, allocations, and cross-currency misuse; confirm invalid arithmetic cannot compile or execute.

---

### [RULE] Snapshot quoted FX and preserve actual settlement FX  (path: /src/payments)
<!-- scope: folder | priority: high | strict -->

A customer-facing quote and the processor's eventual settlement conversion answer different questions. Snapshot the quote rate, source, timestamp, expiration, base and quote currencies, input amount, output amount, spread, and rounding before confirmation. Later, preserve the provider balance movement that contains the actual settlement amount and exchange rate.

- Never recreate a past quote or settlement using the latest market rate.
- Define whether checkout guarantees a quoted amount, accepts movement, or charges directly in presentment currency.
- Keep refund currency and conversion policy explicit, including who bears rate movement and fees.
- Make retries reuse the accepted quote or fail clearly after expiration instead of silently repricing.

Verification: Delay capture past quote expiry, settle at another rate, partially refund, and retry the request; confirm the customer promise and actual money movement remain separately explainable.

---

### [MEMORY] Presentment, settlement, and functional currency stay distinct  (path: /src/ledger)

Name the currency role of every amount. Presentment currency defines what the customer authorized, settlement currency defines what reaches the processor or bank account, and functional or reporting currency defines how finance measures the event. These values may match, but the data model cannot rely on that coincidence.

Post the original currency amount and its conversion evidence together, then recognize realized and unrealized differences under the approved accounting policy. Keep processor conversion fees separate from exchange gains or losses. Aggregate only after conversion at the required event date and rate source. See /src/payments for actual provider settlement evidence and /src/money for unit and rounding rules.

---

### [MEMORY] Rounding belongs to named business boundaries  (path: /src/money)

Rounding after every intermediate operation and rounding only at final display can produce different totals. Define the required precision, mode, and stage for price conversion, tax, discounts, prorations, line allocation, invoice totals, refunds, and ledger postings. Preserve the pre-rounded value or rational inputs where audit or later allocation needs them.

Do not use formatting output as the source for subsequent arithmetic. When a total must equal the sum of displayed lines, allocate the remainder deterministically and record it. Treat a one-unit difference as explainable data, not permission for a floating tolerance everywhere. See /src/ledger for how rounding entries and exchange differences are classified.
