value-objects-money-and-units

Enforces canonical integer-based money and unit value objects in a pure Dart core.

Updated Aug 22, 2026
One-click install
npx skills add https://github.com/zakariaf/NearlyStop --skill value-objects-money-and-units-zakariaf
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: value-objects-money-and-units
Source: https://github.com/zakariaf/NearlyStop/tree/main/.claude/skills/value-objects-money-and-units
Command: npx skills add https://github.com/zakariaf/NearlyStop --skill value-objects-money-and-units-zakariaf

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill requires decimal, clock, and includes scripts (resource) and references (resource) components.

What problem does it solve? Float-based money fields, hardcoded *100 currency scaling, and ad-hoc division of amounts silently corrupt totals and cause off-by-a-cent bugs that users can never re-derive. This Skill enforces a pure-Dart value-object core where every quantity is stored canonically and converted only at the presentation edge. ## Core Features & Use Cases - Canonical money storage: Money is integer minor units plus a Currency whose minor-per-major scale derives from the real ISO-4217 exponent (0 for JPY, 2 for USD, 3 for KWD), never a hardcoded 100. - Single division primitive: Every split of money (shared items, tax, tip, discounts) routes through one largest-remainder allocate() function so parts always sum exactly to the whole, with verified test vectors. - Deterministic time and parsing: Time-reading classes take an injected package:clock Clock instead of DateTime.now(), and amounts are parsed with package:decimal after ASCII digit normalization. - Use Case: When implementing a bill-splitting feature, use this Skill to model Order, LineItem, and Participant as immutable value types linked by stable ids, then compute per-participant totals through the allocate() pipeline so the finals sum to the grand total exactly. ## Quick Start Ask the AI to apply the value-objects-money-and-units rules when defining a Money type or splitting a bill total across participants in the Dart core.

Frequently Asked Questions about value-objects-money-and-units

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I store money in Dart without floating-point errors?

Store money as integer minor units plus a Currency value object, never as double or num. Derive the minor-units-per-major scale from the currency's real ISO-4217 exponent via currency.minorPerMajor instead of hardcoding 100.

How do I split a bill so shares sum exactly to the total?

Route every division through a single integer largest-remainder allocate(amount, weights) primitive. It floors each share, distributes the leftover by descending remainder with a deterministic tie-break, and guarantees the parts sum exactly to the amount.

Why is hardcoding *100 for currency conversion wrong?

A hardcoded 100 is a 100x error for 0-exponent currencies like JPY and a 10x error for 3-exponent currencies like KWD. The scale must come from each currency's actual ISO-4217 exponent, and unknown codes must fail explicitly rather than default to 2 decimals.

Can the money core use Flutter or intl packages?

No, the core is pure Dart and depends only on the decimal and clock packages. Formatting, digit normalization, and storage live in the presentation and data layers, keeping the value objects testable with the plain Dart toolchain.

How do I make time-dependent logic testable in Dart?

Inject package:clock's Clock as a constructor argument instead of calling DateTime.now(). Production passes const Clock() while tests pass Clock.fixed or use fake_async to advance time deterministically.

Why does summing independently rounded shares cause off-by-a-cent bugs?

Each rounded share discards a fractional remainder, and those residuals accumulate so the sum drifts from the true total. Always allocate a known integer total and let the parts absorb the residual, and round percentages to minor units once before allocating.