The arithmetic
No floating-point number touches a rupee
The dullest rule in the product and the one the rest of it rests on. Money is an exact decimal in the database, in the engine and in the browser, and the arithmetic layer raises on a float rather than quietly converting one — by the time a float arrives the precision is already gone, so the fix belongs upstream of the conversion.
Exact decimals end to end
Every monetary column is a fixed-precision decimal, every figure is parsed from text rather than from a float, and rounding happens once at the boundary rather than at each step. Intermediate rounding is how a schedule stops tying to its own lines, and it is invisible until it is embarrassing.
A float is an error, not an input
The money layer raises when handed one instead of coercing it. That is deliberately inconvenient: a coercion here would silently accept the one input that cannot be made exact again, and every figure downstream would inherit it.
The console does no arithmetic
Money reaches the browser as a decimal string and is displayed, not calculated with. A figure computed in a browser is a figure the deliverable cannot trace, which by this product’s own rules means it could never have been rendered anyway.
A figure that cannot be read is not a zero
A malformed amount raises rather than being coerced. A silent zero flows into a total and reconciles perfectly with nothing, which is worse than a row that stops and asks a person to look at it.