Summary
morph::math::Rational has no checked-arithmetic mode. operator+/operator- on plain Rational pairs are fixed-width std::int64_t arithmetic, not saturating and not exception-throwing by signature — at ledger-realistic magnitudes, summing enough rows genuinely triggers real signed-integer overflow (undefined behavior), with no way for a calling application to detect this before committing corrupted state.
Evidence
A binary-search fuzz test (tests/test_ledger_rational_fuzz.cpp, added while implementing rung 5 / ledger) measures the exact boundary empirically, via real Rational::operator+ calls (not a hand-computed estimate): summing dp=2 legs at 10^9 minor units each, the boundary is exactly 9,223,372,037 rows (INT64_MAX / 10^9 + 1).
This isn't a hypothetical: while adding this very fuzz test, an early implementation attempt hit real signed-overflow UB directly (an exponentiation-by-squaring helper doubling one step past what it needed), independently confirmed by two rounds of scoped review before landing a provably-safe version. Rational's own arithmetic operators offer no built-in guard against the same class of bug in application code that doesn't happen to structure its summation as carefully.
Suggested direction
A checked-arithmetic mode — an expected<Rational, Overflow>-returning operator+/operator- alongside the existing noexcept ones, or at minimum a debug-mode overflow assertion — would let a ledger-scale (or otherwise large-magnitude) application detect this before committing corrupted state, rather than relying on the app never summing enough rows to hit the boundary in practice.
Reference
Filed from LASTRADA-Software/morph, branch ladder-ledger-rung5 (not yet merged), as docs/findings/001-rational-checked-arithmetic-mode.md (see that file for the same summary in the ladder's own findings-pipeline format, examples/FINDINGS.md) and tests/test_ledger_rational_fuzz.cpp for the reproducing test.
Summary
morph::math::Rationalhas no checked-arithmetic mode.operator+/operator-on plainRationalpairs are fixed-widthstd::int64_tarithmetic, not saturating and not exception-throwing by signature — at ledger-realistic magnitudes, summing enough rows genuinely triggers real signed-integer overflow (undefined behavior), with no way for a calling application to detect this before committing corrupted state.Evidence
A binary-search fuzz test (
tests/test_ledger_rational_fuzz.cpp, added while implementing rung 5 /ledger) measures the exact boundary empirically, via realRational::operator+calls (not a hand-computed estimate): summing dp=2 legs at 10^9 minor units each, the boundary is exactly 9,223,372,037 rows (INT64_MAX / 10^9 + 1).This isn't a hypothetical: while adding this very fuzz test, an early implementation attempt hit real signed-overflow UB directly (an exponentiation-by-squaring helper doubling one step past what it needed), independently confirmed by two rounds of scoped review before landing a provably-safe version.
Rational's own arithmetic operators offer no built-in guard against the same class of bug in application code that doesn't happen to structure its summation as carefully.Suggested direction
A checked-arithmetic mode — an
expected<Rational, Overflow>-returningoperator+/operator-alongside the existingnoexceptones, or at minimum a debug-mode overflow assertion — would let a ledger-scale (or otherwise large-magnitude) application detect this before committing corrupted state, rather than relying on the app never summing enough rows to hit the boundary in practice.Reference
Filed from
LASTRADA-Software/morph, branchladder-ledger-rung5(not yet merged), asdocs/findings/001-rational-checked-arithmetic-mode.md(see that file for the same summary in the ladder's own findings-pipeline format,examples/FINDINGS.md) andtests/test_ledger_rational_fuzz.cppfor the reproducing test.