kuatia-money crate (Cent, Amount,
CentBacking), kuatia-types (re-export, ToBytes),
kuatia-storage-sql (value column)ADR-0009 fixed monetary amounts as i64 minor units and noted that
widening to a larger integer "is a contained newtype change if a real
asset ever needs it." That contained change is now wanted: a runtime
that defaults to i64 for the common case but can be compiled with
i128 for assets whose precision and supply exceed i64's ~±9.2×10¹⁸
ceiling. At the same time the concrete width should stop leaking:
Cent::value() -> i64, the 8-byte hash encoding, and the BIGINT
column all hard-code the backing. How do we make the backing a
swappable, hidden detail without threading a type parameter through
every posting, movement and store method?
EnvelopeId/PostingId; swapping the width must not silently rehash
the ledger.i128 for them, so the persisted form
must not be a native wide integer.Cent<B: CentBacking>Parameterize the type over its backing and let callers pick.
Pros:
Cons:
Posting, NewPosting,
Movement, Envelope, Account (via CappedOverdraft), every
builder, all of kuatia-core, the Store trait family and the saga.
That is large churn for no domain benefit, since a build uses exactly
one width.Hash/Ord/serde/content-addressing all become generic,
the opposite of "clarity over cleverness."Cent(Backing) + CentBacking trait + cargo-feature selectorCent stays a concrete newtype over a Backing type alias. A
CentBacking trait carries the arithmetic, canonical-byte and string
primitives, with impls for i64 and i128. A cargo feature flips type
Backing between them. The width never appears in a public signature:
reads go through to_string()/parse and through a fixed-width canonical
encoding; value() -> i64 is removed.
Pros:
impl CentBacking for i128 plus --features kuatia-money/i128, with
no change to any downstream crate.Posting, the
store traits and the saga are untouched.to_string, parse, checked math,
Ord, fixed-width canonical bytes) names no concrete integer type, so
the width is hidden.Cons:
value column moving to text loses SQL-side numeric
ordering on amounts. That is already irrelevant, since all arithmetic
is in Rust and no query sorts or ranges on the amount.i64, just widen the column to NUMERICLeave the Rust type as i64 and only make storage wider.
Pros:
Cons:
i128;
the in-memory ceiling is still i64. It solves none of the request.Chosen option: Option 2, a non-generic Cent(Backing) newtype with a
CentBacking trait and a cargo-feature selector, in a new
kuatia-money crate. It delivers the i64↔i128 swap as a second trait
impl behind a feature flag, keeps the default at i64, and hides the
width from every public and stored form, all without threading a generic
through the ledger.
Concretely:
kuatia-money crate (leaf, serde only) holds Cent,
OverflowError, Amount, ParseAmountError, the CentBacking trait,
impl CentBacking for i64/i128, and the Backing alias.
kuatia-types depends on it and re-exports (pub use
kuatia_money::{Cent, Amount, …}), so every existing
kuatia_types::Cent import keeps compiling.#[cfg(not(feature = "i128"))] pub type Backing = i64; /
#[cfg(feature = "i128")] pub type Backing = i128;. Default backing is
i64.value() -> i64 is removed. The public surface is
to_string() (minor-unit string), FromStr, the
From<i32/u32/u8/i8/i64> literal constructors, checked math,
predicates and Ord. Serde for Cent is hand-written to
(de)serialize the string form, so no serialized form reveals the
width.EnvelopeId/PostingId. CANONICAL_VERSION is bumped 1→2 to mark
the new encoding.value column becomes TEXT;
the codec binds cent.to_string() and reads it back with FromStr.
This both hides the width and avoids native 128-bit integers, which
Postgres/SQLite lack.i64
ledger; switching to i128 is one cargo feature and needs no source
edits beyond the (already-written) second trait impl.OverflowError.BIGINT"
consequence; the persisted form is now text. Per project convention
there are no migrations pre-release: 001_init.sql is edited in place
and the database recreated.BIGINT to text).crates/kuatia-money/src/lib.rs (new),
crates/kuatia-types/src/lib.rs,
crates/kuatia-storage-sql/src/lib.rs.